From b5de300ca4d4af199ea39522d5c2f50e89f630c8 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Wed, 26 Oct 2016 12:14:48 +0200 Subject: [PATCH 01/32] Add pskConn --- p2p/net/pnet/psk_conn.go | 91 +++++++++++++++++++++++++++++++++++ p2p/net/pnet/psk_conn_test.go | 79 ++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 p2p/net/pnet/psk_conn.go create mode 100644 p2p/net/pnet/psk_conn_test.go diff --git a/p2p/net/pnet/psk_conn.go b/p2p/net/pnet/psk_conn.go new file mode 100644 index 00000000..29f52007 --- /dev/null +++ b/p2p/net/pnet/psk_conn.go @@ -0,0 +1,91 @@ +package conn + +import ( + "context" + "crypto/cipher" + "crypto/rand" + "errors" + + salsa20 "github.com/davidlazar/go-crypto/salsa20" + mpool "github.com/jbenet/go-msgio/mpool" + iconn "github.com/libp2p/go-libp2p-interface-conn" +) + +// we are using buffer pool as user needs their slice back +// so we can't do XOR cripter in place +var bufPool = mpool.ByteSlicePool + +type pskConn struct { + iconn.Conn + psk *[32]byte + + writeS20 cipher.Stream + readS20 cipher.Stream +} + +func (c *pskConn) Read(out []byte) (int, error) { + if c.readS20 == nil { + nonce := make([]byte, 24) + n, err := c.Conn.Read(nonce) + if err != nil { + return 0, err + } + if n != 24 { + return 0, errors.New("could not read full nonce") + } + c.readS20 = salsa20.New(c.psk, nonce) + } + + maxn := uint32(len(out)) + in := bufPool.Get(maxn).([]byte) // get buffer + defer bufPool.Put(maxn, in) // put the buffer back + + in = in[:maxn] + n, err := c.Conn.Read(in) + if err != nil { + return 0, err + } + + c.readS20.XORKeyStream(out[:n], in[:n]) + + return n, nil +} + +func (c *pskConn) Write(in []byte) (int, error) { + if c.writeS20 == nil { + nonce := make([]byte, 24) + _, err := rand.Read(nonce) + if err != nil { + return 0, err + } + _, err = c.Conn.Write(nonce) + if err != nil { + return 0, err + } + + c.writeS20 = salsa20.New(c.psk, nonce) + } + n := uint32(len(in)) + out := bufPool.Get(n).([]byte) // get buffer + defer bufPool.Put(n, out) // put the buffer back + + out = out[:n] + c.writeS20.XORKeyStream(out, in) + + return c.Conn.Write(out) +} + +var _ iconn.Conn = (*pskConn)(nil) + +func newPSKConn(ctx context.Context, psk *[32]byte, insecure iconn.Conn) (iconn.Conn, error) { + if insecure == nil { + return nil, errors.New("insecure is nil") + } + if psk == nil { + return nil, errors.New("pre-shread key is nil") + } + return &pskConn{ + Conn: insecure, + psk: psk, + }, nil +} diff --git a/p2p/net/pnet/psk_conn_test.go b/p2p/net/pnet/psk_conn_test.go new file mode 100644 index 00000000..7c8877cc --- /dev/null +++ b/p2p/net/pnet/psk_conn_test.go @@ -0,0 +1,79 @@ +package conn + +import ( + "bytes" + "context" + "math/rand" + "testing" + + iconn "github.com/libp2p/go-libp2p-interface-conn" +) + +var testPSK = [32]byte{} // null bytes are as good test key as any other key + +func setupPSKConns(ctx context.Context, t *testing.T) (iconn.Conn, iconn.Conn) { + + conn1, conn2, _, _ := setupSingleConn(t, ctx) + psk1, err := newPSKConn(ctx, &testPSK, conn1) + if err != nil { + t.Fatal(err) + } + psk2, err := newPSKConn(ctx, &testPSK, conn2) + if err != nil { + t.Fatal(err) + } + return psk1, psk2 +} + +func TestPSKSimpelMessges(t *testing.T) { + ctx, cancel := context.WithCancel(context.TODO()) + defer cancel() + + psk1, psk2 := setupPSKConns(ctx, t) + msg1 := []byte("hello world") + out1 := make([]byte, len(msg1)) + + _, err := psk1.Write(msg1) + if err != nil { + t.Fatal(err) + } + n, err := psk2.Read(out1) + if err != nil { + t.Fatal(err) + } + if n != len(out1) { + t.Fatalf("expected to read %d bytes, read: %d", len(out1), n) + } + + if !bytes.Equal(msg1, out1) { + t.Fatalf("input and output are not the same") + } +} + +func TestPSKFragmentation(t *testing.T) { + ctx, cancel := context.WithCancel(context.TODO()) + defer cancel() + + psk1, psk2 := setupPSKConns(ctx, t) + + in := make([]byte, 1000) + _, err := rand.Read(in) + if err != nil { + t.Fatal(err) + } + + out := make([]byte, 100) + + _, err = psk1.Write(in) + if err != nil { + t.Fatal(err) + } + + for i := 0; i < 10; i++ { + _, err = psk2.Read(out) + if !bytes.Equal(in[:100], out) { + t.Fatalf("input and output are not the same") + } + in = in[100:] + } +} From 55d3a73febbbd43674d4ee68cfb708a8f5e1dc61 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Thu, 27 Oct 2016 18:08:36 +0200 Subject: [PATCH 02/32] Disable tests for now and start implementing protector --- p2p/net/pnet/entry.go | 11 +++++++++++ p2p/net/pnet/psk_conn.go | 2 +- p2p/net/pnet/psk_conn_test.go | 10 ++++++---- 3 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 p2p/net/pnet/entry.go diff --git a/p2p/net/pnet/entry.go b/p2p/net/pnet/entry.go new file mode 100644 index 00000000..e4785c8a --- /dev/null +++ b/p2p/net/pnet/entry.go @@ -0,0 +1,11 @@ +package pnet + +import ( + "io" + + ipnet "github.com/libp2p/go-libp2p-interface-pnet" +) + +func NewProtector(input io.Reader) (ipnet.Protector, error) { + return nil, nil +} diff --git a/p2p/net/pnet/psk_conn.go b/p2p/net/pnet/psk_conn.go index 29f52007..d1f3aa1d 100644 --- a/p2p/net/pnet/psk_conn.go +++ b/p2p/net/pnet/psk_conn.go @@ -1,4 +1,4 @@ -package conn +package pnet import ( "context" diff --git a/p2p/net/pnet/psk_conn_test.go b/p2p/net/pnet/psk_conn_test.go index 7c8877cc..40cca34b 100644 --- a/p2p/net/pnet/psk_conn_test.go +++ b/p2p/net/pnet/psk_conn_test.go @@ -1,4 +1,4 @@ -package conn +package pnet import ( "bytes" @@ -12,8 +12,10 @@ import ( var testPSK = [32]byte{} // null bytes are as good test key as any other key func setupPSKConns(ctx context.Context, t *testing.T) (iconn.Conn, iconn.Conn) { + return nil, nil - conn1, conn2, _, _ := setupSingleConn(t, ctx) + //conn1, conn2, _, _ := setupSingleConn(t, ctx) + var conn1, conn2 iconn.Conn psk1, err := newPSKConn(ctx, &testPSK, conn1) if err != nil { t.Fatal(err) @@ -25,7 +27,7 @@ func setupPSKConns(ctx context.Context, t *testing.T) (iconn.Conn, iconn.Conn) { return psk1, psk2 } -func TestPSKSimpelMessges(t *testing.T) { +func XTestPSKSimpelMessges(t *testing.T) { ctx, cancel := context.WithCancel(context.TODO()) defer cancel() @@ -50,7 +52,7 @@ func TestPSKSimpelMessges(t *testing.T) { } } -func TestPSKFragmentation(t *testing.T) { +func XTestPSKFragmentation(t *testing.T) { ctx, cancel := context.WithCancel(context.TODO()) defer cancel() From c6ffeff383b87192a3822a082f5654ab4b75fcfa Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Fri, 28 Oct 2016 01:04:16 +0200 Subject: [PATCH 03/32] Start implementing codecs --- p2p/net/pnet/codec.go | 5 +++++ p2p/net/pnet/entry.go | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 p2p/net/pnet/codec.go diff --git a/p2p/net/pnet/codec.go b/p2p/net/pnet/codec.go new file mode 100644 index 00000000..96c34b6e --- /dev/null +++ b/p2p/net/pnet/codec.go @@ -0,0 +1,5 @@ +package pnet + +var ( + pathPSKv1 = "/key/swarm/psk/1.0.0/" +) diff --git a/p2p/net/pnet/entry.go b/p2p/net/pnet/entry.go index e4785c8a..504b1a04 100644 --- a/p2p/net/pnet/entry.go +++ b/p2p/net/pnet/entry.go @@ -4,8 +4,13 @@ import ( "io" ipnet "github.com/libp2p/go-libp2p-interface-pnet" + mc "github.com/multiformats/go-multicodec" + bmux "github.com/multiformats/go-multicodec/base/mux" ) func NewProtector(input io.Reader) (ipnet.Protector, error) { + input = mc.WrapTransformPathToHeader(input) + _ = bmux.AllBasesMux() + return nil, nil } From 3d3f679ee95e47cf86a309b78350938f6a1ba149 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Fri, 28 Oct 2016 17:30:42 +0200 Subject: [PATCH 04/32] Implement protector --- p2p/net/pnet/codec.go | 34 ++++++++++++++++++++++++++++++++-- p2p/net/pnet/entry.go | 11 +++++------ p2p/net/pnet/protector.go | 16 ++++++++++++++++ p2p/net/pnet/psk_conn.go | 3 +-- 4 files changed, 54 insertions(+), 10 deletions(-) create mode 100644 p2p/net/pnet/protector.go diff --git a/p2p/net/pnet/codec.go b/p2p/net/pnet/codec.go index 96c34b6e..8bf985ce 100644 --- a/p2p/net/pnet/codec.go +++ b/p2p/net/pnet/codec.go @@ -1,5 +1,35 @@ package pnet -var ( - pathPSKv1 = "/key/swarm/psk/1.0.0/" +import ( + "io" + + mc "github.com/multiformats/go-multicodec" + bmux "github.com/multiformats/go-multicodec/base/mux" ) + +var ( + pathPSKv1 = []byte("/key/swarm/psk/1.0.0/") + headerPSKv1 = mc.Header(pathPSKv1) +) + +func decodeV1PSKKey(in io.Reader) (*[32]byte, error) { + var err error + in, err = mc.WrapTransformPathToHeader(in) + if err != nil { + return nil, err + } + err = mc.ConsumeHeader(in, headerPSKv1) + if err != nil { + return nil, err + } + + in, err = mc.WrapTransformPathToHeader(in) + if err != nil { + return nil, err + } + + out := [32]byte{} + + err = bmux.AllBasesMux().Decoder(in).Decode(out) + return &out, err +} diff --git a/p2p/net/pnet/entry.go b/p2p/net/pnet/entry.go index 504b1a04..e0cde4d5 100644 --- a/p2p/net/pnet/entry.go +++ b/p2p/net/pnet/entry.go @@ -4,13 +4,12 @@ import ( "io" ipnet "github.com/libp2p/go-libp2p-interface-pnet" - mc "github.com/multiformats/go-multicodec" - bmux "github.com/multiformats/go-multicodec/base/mux" ) func NewProtector(input io.Reader) (ipnet.Protector, error) { - input = mc.WrapTransformPathToHeader(input) - _ = bmux.AllBasesMux() - - return nil, nil + psk, err := decodeV1PSKKey(input) + if err != nil { + return nil, err + } + return &protector{psk}, nil } diff --git a/p2p/net/pnet/protector.go b/p2p/net/pnet/protector.go new file mode 100644 index 00000000..2759eefc --- /dev/null +++ b/p2p/net/pnet/protector.go @@ -0,0 +1,16 @@ +package pnet + +import ( + iconn "github.com/libp2p/go-libp2p-interface-conn" + ipnet "github.com/libp2p/go-libp2p-interface-pnet" +) + +type protector struct { + psk *[32]byte +} + +var _ ipnet.Protector = (*protector)(nil) + +func (p protector) Protect(in iconn.Conn) (iconn.Conn, error) { + return newPSKConn(p.psk, in) +} diff --git a/p2p/net/pnet/psk_conn.go b/p2p/net/pnet/psk_conn.go index d1f3aa1d..a96e277c 100644 --- a/p2p/net/pnet/psk_conn.go +++ b/p2p/net/pnet/psk_conn.go @@ -1,7 +1,6 @@ package pnet import ( - "context" "crypto/cipher" "crypto/rand" "errors" @@ -77,7 +76,7 @@ func (c *pskConn) Write(in []byte) (int, error) { var _ iconn.Conn = (*pskConn)(nil) -func newPSKConn(ctx context.Context, psk *[32]byte, insecure iconn.Conn) (iconn.Conn, error) { +func newPSKConn(psk *[32]byte, insecure iconn.Conn) (iconn.Conn, error) { if insecure == nil { return nil, errors.New("insecure is nil") } From 95707866880290775cf91d59dbd7cba0baec2a63 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Wed, 2 Nov 2016 17:37:03 +0100 Subject: [PATCH 05/32] Add decoding tests, make conn tests compile --- p2p/net/pnet/codec.go | 8 ++--- p2p/net/pnet/codec_test.go | 61 +++++++++++++++++++++++++++++++++++ p2p/net/pnet/psk_conn_test.go | 4 +-- 3 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 p2p/net/pnet/codec_test.go diff --git a/p2p/net/pnet/codec.go b/p2p/net/pnet/codec.go index 8bf985ce..c013abbc 100644 --- a/p2p/net/pnet/codec.go +++ b/p2p/net/pnet/codec.go @@ -1,6 +1,7 @@ package pnet import ( + "fmt" "io" mc "github.com/multiformats/go-multicodec" @@ -20,16 +21,15 @@ func decodeV1PSKKey(in io.Reader) (*[32]byte, error) { } err = mc.ConsumeHeader(in, headerPSKv1) if err != nil { - return nil, err + return nil, fmt.Errorf("psk header error: %s", err.Error()) } in, err = mc.WrapTransformPathToHeader(in) if err != nil { - return nil, err + return nil, fmt.Errorf("wrapping error: %s", err.Error()) } - out := [32]byte{} - err = bmux.AllBasesMux().Decoder(in).Decode(out) + err = bmux.AllBasesMux().Decoder(in).Decode(out[:]) return &out, err } diff --git a/p2p/net/pnet/codec_test.go b/p2p/net/pnet/codec_test.go new file mode 100644 index 00000000..11d912b6 --- /dev/null +++ b/p2p/net/pnet/codec_test.go @@ -0,0 +1,61 @@ +package pnet + +import ( + "bytes" + "encoding/base64" + "testing" +) + +func bufWithBase(base string) *bytes.Buffer { + + b := &bytes.Buffer{} + b.Write(pathPSKv1) + b.WriteString("\n") + b.WriteString(base) + b.WriteString("\n") + return b +} + +func TestDecodeHex(t *testing.T) { + b := bufWithBase("/base16/") + for i := 0; i < 32; i++ { + b.WriteString("FF") + } + + psk, err := decodeV1PSKKey(b) + if err != nil { + t.Fatal(err) + } + + for _, b := range psk { + if b != 255 { + t.Fatal("byte was wrong") + } + } +} + +func TestDecodeB64(t *testing.T) { + b := bufWithBase("/base64/") + key := make([]byte, 32) + for i := 0; i < 32; i++ { + key[i] = byte(i) + } + + e := base64.NewEncoder(base64.StdEncoding, b) + _, err := e.Write(key) + if err != nil { + t.Fatal(err) + } + + psk, err := decodeV1PSKKey(b) + if err != nil { + t.Fatal(err) + } + + for i, b := range psk { + if b != psk[i] { + t.Fatal("byte was wrong") + } + } + +} diff --git a/p2p/net/pnet/psk_conn_test.go b/p2p/net/pnet/psk_conn_test.go index 40cca34b..d142fa38 100644 --- a/p2p/net/pnet/psk_conn_test.go +++ b/p2p/net/pnet/psk_conn_test.go @@ -16,11 +16,11 @@ func setupPSKConns(ctx context.Context, t *testing.T) (iconn.Conn, iconn.Conn) { //conn1, conn2, _, _ := setupSingleConn(t, ctx) var conn1, conn2 iconn.Conn - psk1, err := newPSKConn(ctx, &testPSK, conn1) + psk1, err := newPSKConn(&testPSK, conn1) if err != nil { t.Fatal(err) } - psk2, err := newPSKConn(ctx, &testPSK, conn2) + psk2, err := newPSKConn(&testPSK, conn2) if err != nil { t.Fatal(err) } From 23d124341e362782372be72b6c0f724f3544e6bc Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Mon, 7 Nov 2016 17:35:13 +0100 Subject: [PATCH 06/32] Enable tests back again using dummy-conn --- p2p/net/pnet/psk_conn_test.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/p2p/net/pnet/psk_conn_test.go b/p2p/net/pnet/psk_conn_test.go index d142fa38..f81b55cf 100644 --- a/p2p/net/pnet/psk_conn_test.go +++ b/p2p/net/pnet/psk_conn_test.go @@ -6,16 +6,18 @@ import ( "math/rand" "testing" + dconn "github.com/Kubuxu/go-libp2p-dummy-conn" iconn "github.com/libp2p/go-libp2p-interface-conn" ) var testPSK = [32]byte{} // null bytes are as good test key as any other key func setupPSKConns(ctx context.Context, t *testing.T) (iconn.Conn, iconn.Conn) { - return nil, nil + conn1, conn2, err := dconn.NewDummyConnPair() + if err != nil { + t.Fatal(err) + } - //conn1, conn2, _, _ := setupSingleConn(t, ctx) - var conn1, conn2 iconn.Conn psk1, err := newPSKConn(&testPSK, conn1) if err != nil { t.Fatal(err) @@ -27,7 +29,7 @@ func setupPSKConns(ctx context.Context, t *testing.T) (iconn.Conn, iconn.Conn) { return psk1, psk2 } -func XTestPSKSimpelMessges(t *testing.T) { +func TestPSKSimpelMessges(t *testing.T) { ctx, cancel := context.WithCancel(context.TODO()) defer cancel() @@ -52,7 +54,7 @@ func XTestPSKSimpelMessges(t *testing.T) { } } -func XTestPSKFragmentation(t *testing.T) { +func TestPSKFragmentation(t *testing.T) { ctx, cancel := context.WithCancel(context.TODO()) defer cancel() From 1128a7c6249e54f53c7efb48e4334892d3155cf9 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Wed, 9 Nov 2016 20:55:29 +0100 Subject: [PATCH 07/32] Move from reader base ctor to bytestring based one --- p2p/net/pnet/entry.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/p2p/net/pnet/entry.go b/p2p/net/pnet/entry.go index e0cde4d5..9add1b01 100644 --- a/p2p/net/pnet/entry.go +++ b/p2p/net/pnet/entry.go @@ -1,13 +1,15 @@ package pnet import ( - "io" + "bytes" ipnet "github.com/libp2p/go-libp2p-interface-pnet" ) -func NewProtector(input io.Reader) (ipnet.Protector, error) { - psk, err := decodeV1PSKKey(input) +func NewProtector(key []byte) (ipnet.Protector, error) { + reader := bytes.NewReader(key) + + psk, err := decodeV1PSKKey(reader) if err != nil { return nil, err } From 92a6e398d64f8efb124551e26af89ad5a509c4b6 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Thu, 24 Nov 2016 16:17:19 +0100 Subject: [PATCH 08/32] Implement fingerprint --- p2p/net/pnet/entry.go | 17 ----------------- p2p/net/pnet/fingerprint.go | 24 ++++++++++++++++++++++++ p2p/net/pnet/fingerprint_test.go | 18 ++++++++++++++++++ p2p/net/pnet/protector.go | 21 ++++++++++++++++++--- 4 files changed, 60 insertions(+), 20 deletions(-) delete mode 100644 p2p/net/pnet/entry.go create mode 100644 p2p/net/pnet/fingerprint.go create mode 100644 p2p/net/pnet/fingerprint_test.go diff --git a/p2p/net/pnet/entry.go b/p2p/net/pnet/entry.go deleted file mode 100644 index 9add1b01..00000000 --- a/p2p/net/pnet/entry.go +++ /dev/null @@ -1,17 +0,0 @@ -package pnet - -import ( - "bytes" - - ipnet "github.com/libp2p/go-libp2p-interface-pnet" -) - -func NewProtector(key []byte) (ipnet.Protector, error) { - reader := bytes.NewReader(key) - - psk, err := decodeV1PSKKey(reader) - if err != nil { - return nil, err - } - return &protector{psk}, nil -} diff --git a/p2p/net/pnet/fingerprint.go b/p2p/net/pnet/fingerprint.go new file mode 100644 index 00000000..978a46b6 --- /dev/null +++ b/p2p/net/pnet/fingerprint.go @@ -0,0 +1,24 @@ +package pnet + +import ( + "golang.org/x/crypto/salsa20" + "golang.org/x/crypto/sha3" +) + +var zero64 = make([]byte, 64) + +func fingerprint(psk *[32]byte) []byte { + enc := make([]byte, 64) + + // We encrypt data first so we don't feed PSK to hash function. + // Salsa20 function is not reversible thus increasing our security margin. + salsa20.XORKeyStream(enc, zero64, []byte("finprint"), psk) + + out := make([]byte, 16) + // Then do Shake-128 hash to reduce its length. + // This way if for some reason Shake is broken and Salsa20 preimage is possible, + // attacker has only half of the bytes necessary to recreate psk. + sha3.ShakeSum128(out, enc) + + return out +} diff --git a/p2p/net/pnet/fingerprint_test.go b/p2p/net/pnet/fingerprint_test.go new file mode 100644 index 00000000..04b238e6 --- /dev/null +++ b/p2p/net/pnet/fingerprint_test.go @@ -0,0 +1,18 @@ +package pnet + +import ( + "bytes" + "testing" +) + +var tpsk *[32]byte = &[32]byte{} + +func TestFingerprintGen(t *testing.T) { + f := fingerprint(tpsk) + exp := []byte{0x70, 0x8a, 0x75, 0xaf, 0xd0, 0x5a, 0xff, 0xb0, 0x87, 0x36, 0xcb, 0xf1, 0x7c, 0x73, 0x77, 0x3e} + + if !bytes.Equal(f, exp) { + t.Fatal("fingerprint different than expected") + } + +} diff --git a/p2p/net/pnet/protector.go b/p2p/net/pnet/protector.go index 2759eefc..3bd15ecc 100644 --- a/p2p/net/pnet/protector.go +++ b/p2p/net/pnet/protector.go @@ -1,16 +1,31 @@ package pnet import ( + "io" + iconn "github.com/libp2p/go-libp2p-interface-conn" ipnet "github.com/libp2p/go-libp2p-interface-pnet" ) -type protector struct { - psk *[32]byte +var _ ipnet.Protector = (*protector)(nil) + +func NewProtector(input io.Reader) (ipnet.Protector, error) { + psk, err := decodeV1PSKKey(input) + if err != nil { + return nil, err + } + f := fingerprint(psk) + return &protector{psk, f}, nil } -var _ ipnet.Protector = (*protector)(nil) +type protector struct { + psk *[32]byte + fingerprint []byte +} func (p protector) Protect(in iconn.Conn) (iconn.Conn, error) { return newPSKConn(p.psk, in) } +func (p protector) Fingerprint() []byte { + return p.fingerprint +} From 8b54290486c11be0fc641cb91de241f226ff1096 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Thu, 24 Nov 2016 16:23:27 +0100 Subject: [PATCH 09/32] Add more info to error --- p2p/net/pnet/psk_conn.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/net/pnet/psk_conn.go b/p2p/net/pnet/psk_conn.go index a96e277c..6afa580c 100644 --- a/p2p/net/pnet/psk_conn.go +++ b/p2p/net/pnet/psk_conn.go @@ -30,7 +30,7 @@ func (c *pskConn) Read(out []byte) (int, error) { return 0, err } if n != 24 { - return 0, errors.New("could not read full nonce") + return 0, errors.New("privnet: could not read full nonce") } c.readS20 = salsa20.New(c.psk, nonce) } From 85eab918ab68e991cc73ec10d45092aaf4044f86 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Fri, 25 Nov 2016 13:24:22 +0100 Subject: [PATCH 10/32] Update interface-pnet to 1.0.1 Add more docs, switch errors to ipnet.NewError --- p2p/net/pnet/protector.go | 6 +++++- p2p/net/pnet/psk_conn.go | 28 +++++++++++++++++----------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/p2p/net/pnet/protector.go b/p2p/net/pnet/protector.go index 3bd15ecc..bfaf1569 100644 --- a/p2p/net/pnet/protector.go +++ b/p2p/net/pnet/protector.go @@ -15,7 +15,11 @@ func NewProtector(input io.Reader) (ipnet.Protector, error) { return nil, err } f := fingerprint(psk) - return &protector{psk, f}, nil + + return &protector{ + psk: psk, + fingerprint: f, + }, nil } type protector struct { diff --git a/p2p/net/pnet/psk_conn.go b/p2p/net/pnet/psk_conn.go index 6afa580c..a98a6926 100644 --- a/p2p/net/pnet/psk_conn.go +++ b/p2p/net/pnet/psk_conn.go @@ -3,16 +3,22 @@ package pnet import ( "crypto/cipher" "crypto/rand" - "errors" salsa20 "github.com/davidlazar/go-crypto/salsa20" mpool "github.com/jbenet/go-msgio/mpool" iconn "github.com/libp2p/go-libp2p-interface-conn" + ipnet "github.com/libp2p/go-libp2p-interface-pnet" ) // we are using buffer pool as user needs their slice back // so we can't do XOR cripter in place -var bufPool = mpool.ByteSlicePool +var ( + bufPool = mpool.ByteSlicePool + + errShortNonce = ipnet.NewError("could not read full nonce") + errInsecureNil = ipnet.NewError("insecure is nil") + errPSKNil = ipnet.NewError("pre-shread key is nil") +) type pskConn struct { iconn.Conn @@ -30,7 +36,7 @@ func (c *pskConn) Read(out []byte) (int, error) { return 0, err } if n != 24 { - return 0, errors.New("privnet: could not read full nonce") + return 0, errShortNonce } c.readS20 = salsa20.New(c.psk, nonce) } @@ -39,13 +45,13 @@ func (c *pskConn) Read(out []byte) (int, error) { in := bufPool.Get(maxn).([]byte) // get buffer defer bufPool.Put(maxn, in) // put the buffer back - in = in[:maxn] - n, err := c.Conn.Read(in) + in = in[:maxn] // truncate to required length + n, err := c.Conn.Read(in) // read to in if err != nil { return 0, err } - c.readS20.XORKeyStream(out[:n], in[:n]) + c.readS20.XORKeyStream(out[:n], in[:n]) // decrypt to out buffer return n, nil } @@ -68,20 +74,20 @@ func (c *pskConn) Write(in []byte) (int, error) { out := bufPool.Get(n).([]byte) // get buffer defer bufPool.Put(n, out) // put the buffer back - out = out[:n] - c.writeS20.XORKeyStream(out, in) + out = out[:n] // truncate to required length + c.writeS20.XORKeyStream(out, in) // encrypt - return c.Conn.Write(out) + return c.Conn.Write(out) // send } var _ iconn.Conn = (*pskConn)(nil) func newPSKConn(psk *[32]byte, insecure iconn.Conn) (iconn.Conn, error) { if insecure == nil { - return nil, errors.New("insecure is nil") + return nil, errInsecureNil } if psk == nil { - return nil, errors.New("pre-shread key is nil") + return nil, errPSKNil } return &pskConn{ Conn: insecure, From 5f77c1f1b9ad151c96e2cdc72215a4cde383374d Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Thu, 16 Feb 2017 13:20:44 +0100 Subject: [PATCH 11/32] Add function to generate PSK key Resolves https://github.com/libp2p/go-libp2p-pnet/issues/5 --- p2p/net/pnet/generate.go | 25 +++++++++++++++++++++++++ p2p/net/pnet/generate_test.go | 32 ++++++++++++++++++++++++++++++++ p2p/net/pnet/protector.go | 2 ++ 3 files changed, 59 insertions(+) create mode 100644 p2p/net/pnet/generate.go create mode 100644 p2p/net/pnet/generate_test.go diff --git a/p2p/net/pnet/generate.go b/p2p/net/pnet/generate.go new file mode 100644 index 00000000..f01257f5 --- /dev/null +++ b/p2p/net/pnet/generate.go @@ -0,0 +1,25 @@ +package pnet + +import ( + "bytes" + "crypto/rand" + "encoding/hex" + "io" +) + +func newLine() io.Reader { + return bytes.NewReader([]byte("\n")) +} + +func GenerateV1PSK() io.Reader { + psk := make([]byte, 32) + rand.Read(psk) + hexPsk := make([]byte, len(psk)*2) + hex.Encode(hexPsk, psk) + + // just a shortcut to NewReader + nr := func(b []byte) io.Reader { + return bytes.NewReader(b) + } + return io.MultiReader(nr(pathPSKv1), newLine(), nr([]byte("/base16/")), newLine(), nr(hexPsk)) +} diff --git a/p2p/net/pnet/generate_test.go b/p2p/net/pnet/generate_test.go new file mode 100644 index 00000000..a6721635 --- /dev/null +++ b/p2p/net/pnet/generate_test.go @@ -0,0 +1,32 @@ +package pnet + +import ( + "bytes" + "io/ioutil" + "testing" +) + +func TestGeneratedPSKCanBeUsed(t *testing.T) { + psk := GenerateV1PSK() + + _, err := NewProtector(psk) + if err != nil { + t.Fatal(err) + } +} + +func TestGeneratedKeysAreDifferent(t *testing.T) { + psk1 := GenerateV1PSK() + psk2 := GenerateV1PSK() + bpsk1, err := ioutil.ReadAll(psk1) + if err != nil { + t.Fatal(err) + } + bpsk2, err := ioutil.ReadAll(psk2) + if err != nil { + t.Fatal(err) + } + if bytes.Equal(bpsk1, bpsk2) { + t.Fatal("generated keys are the same") + } +} diff --git a/p2p/net/pnet/protector.go b/p2p/net/pnet/protector.go index bfaf1569..77cd6b6c 100644 --- a/p2p/net/pnet/protector.go +++ b/p2p/net/pnet/protector.go @@ -9,6 +9,8 @@ import ( var _ ipnet.Protector = (*protector)(nil) +// NewProtector creates ipnet.Protector instance from a io.Reader stream +// that should include Multicodec encoded V1 PSK. func NewProtector(input io.Reader) (ipnet.Protector, error) { psk, err := decodeV1PSKKey(input) if err != nil { From e48088b6662fa4b1a4b428a32bc8177de85f8bb4 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Thu, 16 Feb 2017 14:56:28 +0100 Subject: [PATCH 12/32] Move to go-libp2p-transport.Conn --- p2p/net/pnet/protector.go | 4 ++-- p2p/net/pnet/psk_conn.go | 8 ++++---- p2p/net/pnet/psk_conn_test.go | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/p2p/net/pnet/protector.go b/p2p/net/pnet/protector.go index 77cd6b6c..d613cac7 100644 --- a/p2p/net/pnet/protector.go +++ b/p2p/net/pnet/protector.go @@ -3,8 +3,8 @@ package pnet import ( "io" - iconn "github.com/libp2p/go-libp2p-interface-conn" ipnet "github.com/libp2p/go-libp2p-interface-pnet" + tconn "github.com/libp2p/go-libp2p-transport" ) var _ ipnet.Protector = (*protector)(nil) @@ -29,7 +29,7 @@ type protector struct { fingerprint []byte } -func (p protector) Protect(in iconn.Conn) (iconn.Conn, error) { +func (p protector) Protect(in tconn.Conn) (tconn.Conn, error) { return newPSKConn(p.psk, in) } func (p protector) Fingerprint() []byte { diff --git a/p2p/net/pnet/psk_conn.go b/p2p/net/pnet/psk_conn.go index a98a6926..d60b7ef7 100644 --- a/p2p/net/pnet/psk_conn.go +++ b/p2p/net/pnet/psk_conn.go @@ -6,8 +6,8 @@ import ( salsa20 "github.com/davidlazar/go-crypto/salsa20" mpool "github.com/jbenet/go-msgio/mpool" - iconn "github.com/libp2p/go-libp2p-interface-conn" ipnet "github.com/libp2p/go-libp2p-interface-pnet" + tconn "github.com/libp2p/go-libp2p-transport" ) // we are using buffer pool as user needs their slice back @@ -21,7 +21,7 @@ var ( ) type pskConn struct { - iconn.Conn + tconn.Conn psk *[32]byte writeS20 cipher.Stream @@ -80,9 +80,9 @@ func (c *pskConn) Write(in []byte) (int, error) { return c.Conn.Write(out) // send } -var _ iconn.Conn = (*pskConn)(nil) +var _ tconn.Conn = (*pskConn)(nil) -func newPSKConn(psk *[32]byte, insecure iconn.Conn) (iconn.Conn, error) { +func newPSKConn(psk *[32]byte, insecure tconn.Conn) (tconn.Conn, error) { if insecure == nil { return nil, errInsecureNil } diff --git a/p2p/net/pnet/psk_conn_test.go b/p2p/net/pnet/psk_conn_test.go index f81b55cf..17a3963d 100644 --- a/p2p/net/pnet/psk_conn_test.go +++ b/p2p/net/pnet/psk_conn_test.go @@ -7,12 +7,12 @@ import ( "testing" dconn "github.com/Kubuxu/go-libp2p-dummy-conn" - iconn "github.com/libp2p/go-libp2p-interface-conn" + tconn "github.com/libp2p/go-libp2p-transport" ) var testPSK = [32]byte{} // null bytes are as good test key as any other key -func setupPSKConns(ctx context.Context, t *testing.T) (iconn.Conn, iconn.Conn) { +func setupPSKConns(ctx context.Context, t *testing.T) (tconn.Conn, tconn.Conn) { conn1, conn2, err := dconn.NewDummyConnPair() if err != nil { t.Fatal(err) From 93471c19633a5ad7b240220404d1e801022c424c Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Fri, 17 Feb 2017 14:24:50 +0100 Subject: [PATCH 13/32] Add docs to GenerateV1PSK --- p2p/net/pnet/generate.go | 1 + 1 file changed, 1 insertion(+) diff --git a/p2p/net/pnet/generate.go b/p2p/net/pnet/generate.go index f01257f5..f44dfe64 100644 --- a/p2p/net/pnet/generate.go +++ b/p2p/net/pnet/generate.go @@ -11,6 +11,7 @@ func newLine() io.Reader { return bytes.NewReader([]byte("\n")) } +// GenerateV1PSK generates new PSK key that can be used with NewProtector func GenerateV1PSK() io.Reader { psk := make([]byte, 32) rand.Read(psk) From 80bf4d2a41b6f7b6db28fd2f73ec6df8bbd3293a Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sat, 27 May 2017 20:17:34 +0800 Subject: [PATCH 14/32] read nonces, even if they are fragmented io.ReadFull is garantueed to read the complete length of the buffer (or to return an error if that fails). This way, reading the nonce also succeeds when multiple Read calls are necessary. --- p2p/net/pnet/psk_conn.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/p2p/net/pnet/psk_conn.go b/p2p/net/pnet/psk_conn.go index d60b7ef7..cce58521 100644 --- a/p2p/net/pnet/psk_conn.go +++ b/p2p/net/pnet/psk_conn.go @@ -3,6 +3,7 @@ package pnet import ( "crypto/cipher" "crypto/rand" + "io" salsa20 "github.com/davidlazar/go-crypto/salsa20" mpool "github.com/jbenet/go-msgio/mpool" @@ -31,11 +32,8 @@ type pskConn struct { func (c *pskConn) Read(out []byte) (int, error) { if c.readS20 == nil { nonce := make([]byte, 24) - n, err := c.Conn.Read(nonce) + _, err := io.ReadFull(c.Conn, nonce) if err != nil { - return 0, err - } - if n != 24 { return 0, errShortNonce } c.readS20 = salsa20.New(c.psk, nonce) From b2e8111dbcd149aac80d5c61ce2cdd86db184519 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Wed, 19 Jul 2017 09:58:25 +0200 Subject: [PATCH 15/32] add NewV1ProtectorFromBytes and tests for it --- p2p/net/pnet/codec.go | 2 +- p2p/net/pnet/codec_test.go | 4 ++-- p2p/net/pnet/generate.go | 22 +++++++++++++++++----- p2p/net/pnet/generate_test.go | 31 +++++++++++++++++++++++++++---- p2p/net/pnet/protector.go | 9 ++++++--- 5 files changed, 53 insertions(+), 15 deletions(-) diff --git a/p2p/net/pnet/codec.go b/p2p/net/pnet/codec.go index c013abbc..ac698283 100644 --- a/p2p/net/pnet/codec.go +++ b/p2p/net/pnet/codec.go @@ -13,7 +13,7 @@ var ( headerPSKv1 = mc.Header(pathPSKv1) ) -func decodeV1PSKKey(in io.Reader) (*[32]byte, error) { +func decodeV1PSK(in io.Reader) (*[32]byte, error) { var err error in, err = mc.WrapTransformPathToHeader(in) if err != nil { diff --git a/p2p/net/pnet/codec_test.go b/p2p/net/pnet/codec_test.go index 11d912b6..04afe65f 100644 --- a/p2p/net/pnet/codec_test.go +++ b/p2p/net/pnet/codec_test.go @@ -22,7 +22,7 @@ func TestDecodeHex(t *testing.T) { b.WriteString("FF") } - psk, err := decodeV1PSKKey(b) + psk, err := decodeV1PSK(b) if err != nil { t.Fatal(err) } @@ -47,7 +47,7 @@ func TestDecodeB64(t *testing.T) { t.Fatal(err) } - psk, err := decodeV1PSKKey(b) + psk, err := decodeV1PSK(b) if err != nil { t.Fatal(err) } diff --git a/p2p/net/pnet/generate.go b/p2p/net/pnet/generate.go index f44dfe64..cf220ced 100644 --- a/p2p/net/pnet/generate.go +++ b/p2p/net/pnet/generate.go @@ -12,15 +12,27 @@ func newLine() io.Reader { } // GenerateV1PSK generates new PSK key that can be used with NewProtector -func GenerateV1PSK() io.Reader { - psk := make([]byte, 32) - rand.Read(psk) +func GenerateV1PSK() (io.Reader, error) { + psk, err := GenerateV1Bytes() + if err != nil { + return nil, err + } + hexPsk := make([]byte, len(psk)*2) - hex.Encode(hexPsk, psk) + hex.Encode(hexPsk, psk[:]) // just a shortcut to NewReader nr := func(b []byte) io.Reader { return bytes.NewReader(b) } - return io.MultiReader(nr(pathPSKv1), newLine(), nr([]byte("/base16/")), newLine(), nr(hexPsk)) + return io.MultiReader(nr(pathPSKv1), newLine(), nr([]byte("/base16/")), newLine(), nr(hexPsk)), nil +} + +func GenerateV1Bytes() (*[32]byte, error) { + psk := [32]byte{} + _, err := rand.Read(psk[:]) + if err != nil { + return nil, err + } + return &psk, nil } diff --git a/p2p/net/pnet/generate_test.go b/p2p/net/pnet/generate_test.go index a6721635..e06e4c1e 100644 --- a/p2p/net/pnet/generate_test.go +++ b/p2p/net/pnet/generate_test.go @@ -7,17 +7,26 @@ import ( ) func TestGeneratedPSKCanBeUsed(t *testing.T) { - psk := GenerateV1PSK() + psk, err := GenerateV1PSK() + if err != nil { + t.Fatal(err) + } - _, err := NewProtector(psk) + _, err = NewProtector(psk) if err != nil { t.Fatal(err) } } func TestGeneratedKeysAreDifferent(t *testing.T) { - psk1 := GenerateV1PSK() - psk2 := GenerateV1PSK() + psk1, err := GenerateV1PSK() + if err != nil { + t.Fatal(err) + } + psk2, err := GenerateV1PSK() + if err != nil { + t.Fatal(err) + } bpsk1, err := ioutil.ReadAll(psk1) if err != nil { t.Fatal(err) @@ -30,3 +39,17 @@ func TestGeneratedKeysAreDifferent(t *testing.T) { t.Fatal("generated keys are the same") } } + +func TestGeneratedV1BytesAreDifferent(t *testing.T) { + b1, err := GenerateV1Bytes() + if err != nil { + t.Fatal(err) + } + b2, err := GenerateV1Bytes() + if err != nil { + t.Fatal(err) + } + if bytes.Equal(b1[:], b2[:]) { + t.Fatal("generated keys are the same") + } +} diff --git a/p2p/net/pnet/protector.go b/p2p/net/pnet/protector.go index d613cac7..3442150a 100644 --- a/p2p/net/pnet/protector.go +++ b/p2p/net/pnet/protector.go @@ -12,15 +12,18 @@ var _ ipnet.Protector = (*protector)(nil) // NewProtector creates ipnet.Protector instance from a io.Reader stream // that should include Multicodec encoded V1 PSK. func NewProtector(input io.Reader) (ipnet.Protector, error) { - psk, err := decodeV1PSKKey(input) + psk, err := decodeV1PSK(input) if err != nil { return nil, err } - f := fingerprint(psk) + return NewV1ProtectorFromBytes(psk) +} +// NewV1ProtectorFromBytes creates ipnet.Protector of the V1 version. +func NewV1ProtectorFromBytes(psk *[32]byte) (ipnet.Protector, error) { return &protector{ psk: psk, - fingerprint: f, + fingerprint: fingerprint(psk), }, nil } From 191577982ff857e14c46907e0b94c8ff62c30714 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 20 Nov 2017 13:16:19 -0800 Subject: [PATCH 16/32] update msgio --- p2p/net/pnet/psk_conn.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/net/pnet/psk_conn.go b/p2p/net/pnet/psk_conn.go index cce58521..a24968a1 100644 --- a/p2p/net/pnet/psk_conn.go +++ b/p2p/net/pnet/psk_conn.go @@ -6,9 +6,9 @@ import ( "io" salsa20 "github.com/davidlazar/go-crypto/salsa20" - mpool "github.com/jbenet/go-msgio/mpool" ipnet "github.com/libp2p/go-libp2p-interface-pnet" tconn "github.com/libp2p/go-libp2p-transport" + mpool "github.com/libp2p/go-msgio/mpool" ) // we are using buffer pool as user needs their slice back From 9e983dad027b62c91427102002d3b08d6a8b1057 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 20 Nov 2017 13:17:46 -0800 Subject: [PATCH 17/32] don't copy the buffer pool use the global one --- p2p/net/pnet/psk_conn.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/p2p/net/pnet/psk_conn.go b/p2p/net/pnet/psk_conn.go index a24968a1..a6e42471 100644 --- a/p2p/net/pnet/psk_conn.go +++ b/p2p/net/pnet/psk_conn.go @@ -14,8 +14,6 @@ import ( // we are using buffer pool as user needs their slice back // so we can't do XOR cripter in place var ( - bufPool = mpool.ByteSlicePool - errShortNonce = ipnet.NewError("could not read full nonce") errInsecureNil = ipnet.NewError("insecure is nil") errPSKNil = ipnet.NewError("pre-shread key is nil") @@ -40,8 +38,8 @@ func (c *pskConn) Read(out []byte) (int, error) { } maxn := uint32(len(out)) - in := bufPool.Get(maxn).([]byte) // get buffer - defer bufPool.Put(maxn, in) // put the buffer back + in := mpool.ByteSlicePool.Get(maxn).([]byte) // get buffer + defer mpool.ByteSlicePool.Put(maxn, in) // put the buffer back in = in[:maxn] // truncate to required length n, err := c.Conn.Read(in) // read to in @@ -69,8 +67,8 @@ func (c *pskConn) Write(in []byte) (int, error) { c.writeS20 = salsa20.New(c.psk, nonce) } n := uint32(len(in)) - out := bufPool.Get(n).([]byte) // get buffer - defer bufPool.Put(n, out) // put the buffer back + out := mpool.ByteSlicePool.Get(n).([]byte) // get buffer + defer mpool.ByteSlicePool.Put(n, out) // put the buffer back out = out[:n] // truncate to required length c.writeS20.XORKeyStream(out, in) // encrypt From a1ed19f911945c3c28da82635d5cac02811851ea Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 20 Nov 2017 16:02:11 -0800 Subject: [PATCH 18/32] gx: update deps * pull through libp2p-transport update * update moved go-libp2p-dummy-conn --- p2p/net/pnet/psk_conn_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/net/pnet/psk_conn_test.go b/p2p/net/pnet/psk_conn_test.go index 17a3963d..c76f474a 100644 --- a/p2p/net/pnet/psk_conn_test.go +++ b/p2p/net/pnet/psk_conn_test.go @@ -6,7 +6,7 @@ import ( "math/rand" "testing" - dconn "github.com/Kubuxu/go-libp2p-dummy-conn" + dconn "github.com/libp2p/go-libp2p-dummy-conn" tconn "github.com/libp2p/go-libp2p-transport" ) From 02aa6480abcfdaf8887dcfb186be29a4044098c6 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Wed, 7 Mar 2018 20:00:03 -0800 Subject: [PATCH 19/32] correctly handle Read errors/EOF Read can read data *and* return an error. --- p2p/net/pnet/psk_conn.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/p2p/net/pnet/psk_conn.go b/p2p/net/pnet/psk_conn.go index a6e42471..b9fc750b 100644 --- a/p2p/net/pnet/psk_conn.go +++ b/p2p/net/pnet/psk_conn.go @@ -43,13 +43,10 @@ func (c *pskConn) Read(out []byte) (int, error) { in = in[:maxn] // truncate to required length n, err := c.Conn.Read(in) // read to in - if err != nil { - return 0, err + if n > 0 { + c.readS20.XORKeyStream(out[:n], in[:n]) // decrypt to out buffer } - - c.readS20.XORKeyStream(out[:n], in[:n]) // decrypt to out buffer - - return n, nil + return n, err } func (c *pskConn) Write(in []byte) (int, error) { From cec0aa6b9c219dfe31edccde608e3a6e5bafd2b1 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 20 Apr 2018 09:28:12 +0900 Subject: [PATCH 20/32] annotate the "malformed key" error from pnet protector --- p2p/net/pnet/protector.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/p2p/net/pnet/protector.go b/p2p/net/pnet/protector.go index 3442150a..72446c2c 100644 --- a/p2p/net/pnet/protector.go +++ b/p2p/net/pnet/protector.go @@ -1,6 +1,7 @@ package pnet import ( + "fmt" "io" ipnet "github.com/libp2p/go-libp2p-interface-pnet" @@ -14,7 +15,7 @@ var _ ipnet.Protector = (*protector)(nil) func NewProtector(input io.Reader) (ipnet.Protector, error) { psk, err := decodeV1PSK(input) if err != nil { - return nil, err + return nil, fmt.Errorf("malformed private network key: %s", err) } return NewV1ProtectorFromBytes(psk) } From 34c0789b9de1128edfbd225c5c5c1864dd7e4bd6 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 18 Jan 2018 13:31:54 -0800 Subject: [PATCH 21/32] wrap net conns, not transport conns We now "protect" below the transport layer. Also, make the tests work without the dummy conn package (one fewer deps). --- p2p/net/pnet/protector.go | 4 ++-- p2p/net/pnet/psk_conn.go | 8 +++---- p2p/net/pnet/psk_conn_test.go | 40 +++++++++++++++++++++-------------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/p2p/net/pnet/protector.go b/p2p/net/pnet/protector.go index 72446c2c..38706817 100644 --- a/p2p/net/pnet/protector.go +++ b/p2p/net/pnet/protector.go @@ -3,9 +3,9 @@ package pnet import ( "fmt" "io" + "net" ipnet "github.com/libp2p/go-libp2p-interface-pnet" - tconn "github.com/libp2p/go-libp2p-transport" ) var _ ipnet.Protector = (*protector)(nil) @@ -33,7 +33,7 @@ type protector struct { fingerprint []byte } -func (p protector) Protect(in tconn.Conn) (tconn.Conn, error) { +func (p protector) Protect(in net.Conn) (net.Conn, error) { return newPSKConn(p.psk, in) } func (p protector) Fingerprint() []byte { diff --git a/p2p/net/pnet/psk_conn.go b/p2p/net/pnet/psk_conn.go index b9fc750b..18dbada1 100644 --- a/p2p/net/pnet/psk_conn.go +++ b/p2p/net/pnet/psk_conn.go @@ -4,10 +4,10 @@ import ( "crypto/cipher" "crypto/rand" "io" + "net" salsa20 "github.com/davidlazar/go-crypto/salsa20" ipnet "github.com/libp2p/go-libp2p-interface-pnet" - tconn "github.com/libp2p/go-libp2p-transport" mpool "github.com/libp2p/go-msgio/mpool" ) @@ -20,7 +20,7 @@ var ( ) type pskConn struct { - tconn.Conn + net.Conn psk *[32]byte writeS20 cipher.Stream @@ -73,9 +73,9 @@ func (c *pskConn) Write(in []byte) (int, error) { return c.Conn.Write(out) // send } -var _ tconn.Conn = (*pskConn)(nil) +var _ net.Conn = (*pskConn)(nil) -func newPSKConn(psk *[32]byte, insecure tconn.Conn) (tconn.Conn, error) { +func newPSKConn(psk *[32]byte, insecure net.Conn) (net.Conn, error) { if insecure == nil { return nil, errInsecureNil } diff --git a/p2p/net/pnet/psk_conn_test.go b/p2p/net/pnet/psk_conn_test.go index c76f474a..23108f40 100644 --- a/p2p/net/pnet/psk_conn_test.go +++ b/p2p/net/pnet/psk_conn_test.go @@ -4,19 +4,14 @@ import ( "bytes" "context" "math/rand" + "net" "testing" - - dconn "github.com/libp2p/go-libp2p-dummy-conn" - tconn "github.com/libp2p/go-libp2p-transport" ) var testPSK = [32]byte{} // null bytes are as good test key as any other key -func setupPSKConns(ctx context.Context, t *testing.T) (tconn.Conn, tconn.Conn) { - conn1, conn2, err := dconn.NewDummyConnPair() - if err != nil { - t.Fatal(err) - } +func setupPSKConns(ctx context.Context, t *testing.T) (net.Conn, net.Conn) { + conn1, conn2 := net.Pipe() psk1, err := newPSKConn(&testPSK, conn1) if err != nil { @@ -37,14 +32,21 @@ func TestPSKSimpelMessges(t *testing.T) { msg1 := []byte("hello world") out1 := make([]byte, len(msg1)) - _, err := psk1.Write(msg1) - if err != nil { - t.Fatal(err) - } + wch := make(chan error) + go func() { + _, err := psk1.Write(msg1) + wch <- err + }() n, err := psk2.Read(out1) if err != nil { t.Fatal(err) } + + err = <-wch + if err != nil { + t.Fatal(err) + } + if n != len(out1) { t.Fatalf("expected to read %d bytes, read: %d", len(out1), n) } @@ -68,10 +70,11 @@ func TestPSKFragmentation(t *testing.T) { out := make([]byte, 100) - _, err = psk1.Write(in) - if err != nil { - t.Fatal(err) - } + wch := make(chan error) + go func() { + _, err := psk1.Write(in) + wch <- err + }() for i := 0; i < 10; i++ { _, err = psk2.Read(out) @@ -80,4 +83,9 @@ func TestPSKFragmentation(t *testing.T) { } in = in[100:] } + + err = <-wch + if err != nil { + t.Fatal(err) + } } From fbcd00db5fb4b81f0459ca07024cd463d7418b0e Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 25 Sep 2018 15:52:41 -0700 Subject: [PATCH 22/32] avoid the buffer-pool on read We can xor in-place (this is what secio does). --- p2p/net/pnet/psk_conn.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/p2p/net/pnet/psk_conn.go b/p2p/net/pnet/psk_conn.go index 18dbada1..a2e9e1e1 100644 --- a/p2p/net/pnet/psk_conn.go +++ b/p2p/net/pnet/psk_conn.go @@ -37,14 +37,9 @@ func (c *pskConn) Read(out []byte) (int, error) { c.readS20 = salsa20.New(c.psk, nonce) } - maxn := uint32(len(out)) - in := mpool.ByteSlicePool.Get(maxn).([]byte) // get buffer - defer mpool.ByteSlicePool.Put(maxn, in) // put the buffer back - - in = in[:maxn] // truncate to required length - n, err := c.Conn.Read(in) // read to in + n, err := c.Conn.Read(out) // read to in if n > 0 { - c.readS20.XORKeyStream(out[:n], in[:n]) // decrypt to out buffer + c.readS20.XORKeyStream(out[:n], out[:n]) // decrypt to out buffer } return n, err } From f9f82398e1a763e2666cf0238e00dd64f7252478 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 25 Sep 2018 15:53:24 -0700 Subject: [PATCH 23/32] switch to go-buffer-pool It has a nicer interface and we don't even need the rest of the msgio stuff. --- p2p/net/pnet/psk_conn.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/p2p/net/pnet/psk_conn.go b/p2p/net/pnet/psk_conn.go index a2e9e1e1..5b16ef7a 100644 --- a/p2p/net/pnet/psk_conn.go +++ b/p2p/net/pnet/psk_conn.go @@ -7,8 +7,8 @@ import ( "net" salsa20 "github.com/davidlazar/go-crypto/salsa20" + pool "github.com/libp2p/go-buffer-pool" ipnet "github.com/libp2p/go-libp2p-interface-pnet" - mpool "github.com/libp2p/go-msgio/mpool" ) // we are using buffer pool as user needs their slice back @@ -58,11 +58,9 @@ func (c *pskConn) Write(in []byte) (int, error) { c.writeS20 = salsa20.New(c.psk, nonce) } - n := uint32(len(in)) - out := mpool.ByteSlicePool.Get(n).([]byte) // get buffer - defer mpool.ByteSlicePool.Put(n, out) // put the buffer back + out := pool.Get(len(in)) + defer pool.Put(out) - out = out[:n] // truncate to required length c.writeS20.XORKeyStream(out, in) // encrypt return c.Conn.Write(out) // send From 767f2b74c4b248a52e5ae2dfd5e6e7a87bc5c763 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 21 Mar 2019 18:05:11 -0700 Subject: [PATCH 24/32] remove dependency on go-multicodec It's unmaintained and pulls in github.com/whyrusleeping/cbor. This patch explicitly re-implements the minimally needed features. Also fixes #12. --- p2p/net/pnet/codec.go | 68 +++++++++++++++++++++++++++----------- p2p/net/pnet/codec_test.go | 4 +++ 2 files changed, 52 insertions(+), 20 deletions(-) diff --git a/p2p/net/pnet/codec.go b/p2p/net/pnet/codec.go index ac698283..9dde327b 100644 --- a/p2p/net/pnet/codec.go +++ b/p2p/net/pnet/codec.go @@ -1,35 +1,63 @@ package pnet import ( + "bufio" + "bytes" + "encoding/base64" + "encoding/hex" "fmt" "io" - - mc "github.com/multiformats/go-multicodec" - bmux "github.com/multiformats/go-multicodec/base/mux" ) var ( - pathPSKv1 = []byte("/key/swarm/psk/1.0.0/") - headerPSKv1 = mc.Header(pathPSKv1) + pathPSKv1 = []byte("/key/swarm/psk/1.0.0/") + pathBase16 = "/base16/" + pathBase64 = "/base64/" ) -func decodeV1PSK(in io.Reader) (*[32]byte, error) { - var err error - in, err = mc.WrapTransformPathToHeader(in) +func readHeader(r *bufio.Reader) ([]byte, error) { + header, err := r.ReadBytes('\n') if err != nil { return nil, err } - err = mc.ConsumeHeader(in, headerPSKv1) - if err != nil { - return nil, fmt.Errorf("psk header error: %s", err.Error()) - } - in, err = mc.WrapTransformPathToHeader(in) - if err != nil { - return nil, fmt.Errorf("wrapping error: %s", err.Error()) - } - out := [32]byte{} - - err = bmux.AllBasesMux().Decoder(in).Decode(out[:]) - return &out, err + return bytes.TrimRight(header, "\r\n"), nil +} + +func expectHeader(r *bufio.Reader, expected []byte) error { + header, err := readHeader(r) + if err != nil { + return err + } + if !bytes.Equal(header, expected) { + return fmt.Errorf("expected file header %s, got: %s", pathPSKv1, header) + } + return nil +} + +func decodeV1PSK(in io.Reader) (*[32]byte, error) { + reader := bufio.NewReader(in) + if err := expectHeader(reader, pathPSKv1); err != nil { + return nil, err + } + header, err := readHeader(reader) + if err != nil { + return nil, err + } + + var decoder io.Reader + switch string(header) { + case pathBase16: + decoder = hex.NewDecoder(reader) + case pathBase64: + decoder = base64.NewDecoder(base64.StdEncoding, reader) + default: + return nil, fmt.Errorf("unknown encoding: %s", header) + } + out := new([32]byte) + _, err = io.ReadFull(decoder, out[:]) + if err != nil { + return nil, err + } + return out, nil } diff --git a/p2p/net/pnet/codec_test.go b/p2p/net/pnet/codec_test.go index 04afe65f..8167b34d 100644 --- a/p2p/net/pnet/codec_test.go +++ b/p2p/net/pnet/codec_test.go @@ -46,6 +46,10 @@ func TestDecodeB64(t *testing.T) { if err != nil { t.Fatal(err) } + err = e.Close() + if err != nil { + t.Fatal(err) + } psk, err := decodeV1PSK(b) if err != nil { From e90259bca678a407ce889627cdcedc72a14f1fa2 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 21 Mar 2019 18:10:44 -0700 Subject: [PATCH 25/32] test decoding on windows --- p2p/net/pnet/codec_test.go | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/p2p/net/pnet/codec_test.go b/p2p/net/pnet/codec_test.go index 8167b34d..e6d8409f 100644 --- a/p2p/net/pnet/codec_test.go +++ b/p2p/net/pnet/codec_test.go @@ -6,18 +6,29 @@ import ( "testing" ) -func bufWithBase(base string) *bytes.Buffer { +func bufWithBase(base string, windows bool) *bytes.Buffer { b := &bytes.Buffer{} b.Write(pathPSKv1) + if windows { + b.WriteString("\r") + } b.WriteString("\n") b.WriteString(base) + if windows { + b.WriteString("\r") + } b.WriteString("\n") return b } func TestDecodeHex(t *testing.T) { - b := bufWithBase("/base16/") + testDecodeHex(t, true) + testDecodeHex(t, false) +} + +func testDecodeHex(t *testing.T, windows bool) { + b := bufWithBase("/base16/", windows) for i := 0; i < 32; i++ { b.WriteString("FF") } @@ -35,7 +46,12 @@ func TestDecodeHex(t *testing.T) { } func TestDecodeB64(t *testing.T) { - b := bufWithBase("/base64/") + testDecodeB64(t, true) + testDecodeB64(t, false) +} + +func testDecodeB64(t *testing.T, windows bool) { + b := bufWithBase("/base64/", windows) key := make([]byte, 32) for i := 0; i < 32; i++ { key[i] = byte(i) From 8c9004d36b9b3802faa20a7994f114b511e07491 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Fri, 22 Mar 2019 02:44:36 +0100 Subject: [PATCH 26/32] Add bad encoding test case License: MIT Signed-off-by: Jakub Sztandera --- p2p/net/pnet/codec_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/p2p/net/pnet/codec_test.go b/p2p/net/pnet/codec_test.go index e6d8409f..e59d9b2b 100644 --- a/p2p/net/pnet/codec_test.go +++ b/p2p/net/pnet/codec_test.go @@ -27,6 +27,20 @@ func TestDecodeHex(t *testing.T) { testDecodeHex(t, false) } +func TestDecodeBad(t *testing.T) { + testDecodeBad(t, true) + testDecodeBad(t, false) +} +func testDecodeBad(t *testing.T, windows bool) { + b := bufWithBase("/verybadbase/", windows) + b.WriteString("Have fun decoding that key") + + _, err := decodeV1PSK(b) + if err == nil { + t.Fatal("expected 'unknown encoding' got nil") + } +} + func testDecodeHex(t *testing.T, windows bool) { b := bufWithBase("/base16/", windows) for i := 0; i < 32; i++ { From 50f09fade6a7313034d73c720ffe06df57e2d0b7 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 21 Mar 2019 18:50:51 -0700 Subject: [PATCH 27/32] add back support for binary encoding --- p2p/net/pnet/codec.go | 3 +++ p2p/net/pnet/codec_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/p2p/net/pnet/codec.go b/p2p/net/pnet/codec.go index 9dde327b..19b929f6 100644 --- a/p2p/net/pnet/codec.go +++ b/p2p/net/pnet/codec.go @@ -11,6 +11,7 @@ import ( var ( pathPSKv1 = []byte("/key/swarm/psk/1.0.0/") + pathBin = "/bin/" pathBase16 = "/base16/" pathBase64 = "/base64/" ) @@ -51,6 +52,8 @@ func decodeV1PSK(in io.Reader) (*[32]byte, error) { decoder = hex.NewDecoder(reader) case pathBase64: decoder = base64.NewDecoder(base64.StdEncoding, reader) + case pathBin: + decoder = reader default: return nil, fmt.Errorf("unknown encoding: %s", header) } diff --git a/p2p/net/pnet/codec_test.go b/p2p/net/pnet/codec_test.go index e59d9b2b..233f3419 100644 --- a/p2p/net/pnet/codec_test.go +++ b/p2p/net/pnet/codec_test.go @@ -31,6 +31,7 @@ func TestDecodeBad(t *testing.T) { testDecodeBad(t, true) testDecodeBad(t, false) } + func testDecodeBad(t *testing.T, windows bool) { b := bufWithBase("/verybadbase/", windows) b.WriteString("Have fun decoding that key") @@ -93,3 +94,30 @@ func testDecodeB64(t *testing.T, windows bool) { } } + +func TestDecodeBin(t *testing.T) { + testDecodeBin(t, true) + testDecodeBin(t, false) +} + +func testDecodeBin(t *testing.T, windows bool) { + b := bufWithBase("/bin/", windows) + key := make([]byte, 32) + for i := 0; i < 32; i++ { + key[i] = byte(i) + } + + b.Write(key) + + psk, err := decodeV1PSK(b) + if err != nil { + t.Fatal(err) + } + + for i, b := range psk { + if b != psk[i] { + t.Fatal("byte was wrong") + } + } + +} From 506082e1bd0d4ab3c6943d75e6b84ced689e35f8 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Tue, 9 Apr 2019 11:58:29 -0400 Subject: [PATCH 28/32] update readme badges --- p2p/net/pnet/.#README.md | 1 + 1 file changed, 1 insertion(+) create mode 120000 p2p/net/pnet/.#README.md diff --git a/p2p/net/pnet/.#README.md b/p2p/net/pnet/.#README.md new file mode 120000 index 00000000..2cb729be --- /dev/null +++ b/p2p/net/pnet/.#README.md @@ -0,0 +1 @@ +yusef@Yusefs-MacBook-Pro-2.local.40096 \ No newline at end of file From 6793f6f3e0b1d7fb5b604dd24f3aac90b4cc2059 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Tue, 9 Apr 2019 11:58:55 -0400 Subject: [PATCH 29/32] update readme badges --- p2p/net/pnet/.#README.md | 1 - 1 file changed, 1 deletion(-) delete mode 120000 p2p/net/pnet/.#README.md diff --git a/p2p/net/pnet/.#README.md b/p2p/net/pnet/.#README.md deleted file mode 120000 index 2cb729be..00000000 --- a/p2p/net/pnet/.#README.md +++ /dev/null @@ -1 +0,0 @@ -yusef@Yusefs-MacBook-Pro-2.local.40096 \ No newline at end of file From 3ca427f3bc169859acfffafa7ca53e8a9d426dcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Sat, 25 May 2019 13:27:36 +0100 Subject: [PATCH 30/32] Consolidate abstractions and core types into go-libp2p-core (#27) --- p2p/net/pnet/protector.go | 2 +- p2p/net/pnet/psk_conn.go | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/p2p/net/pnet/protector.go b/p2p/net/pnet/protector.go index 38706817..8b8d2dd0 100644 --- a/p2p/net/pnet/protector.go +++ b/p2p/net/pnet/protector.go @@ -5,7 +5,7 @@ import ( "io" "net" - ipnet "github.com/libp2p/go-libp2p-interface-pnet" + ipnet "github.com/libp2p/go-libp2p-core/pnet" ) var _ ipnet.Protector = (*protector)(nil) diff --git a/p2p/net/pnet/psk_conn.go b/p2p/net/pnet/psk_conn.go index 5b16ef7a..5d35d879 100644 --- a/p2p/net/pnet/psk_conn.go +++ b/p2p/net/pnet/psk_conn.go @@ -6,17 +6,18 @@ import ( "io" "net" - salsa20 "github.com/davidlazar/go-crypto/salsa20" + "github.com/libp2p/go-libp2p-core/pnet" + + "github.com/davidlazar/go-crypto/salsa20" pool "github.com/libp2p/go-buffer-pool" - ipnet "github.com/libp2p/go-libp2p-interface-pnet" ) // we are using buffer pool as user needs their slice back // so we can't do XOR cripter in place var ( - errShortNonce = ipnet.NewError("could not read full nonce") - errInsecureNil = ipnet.NewError("insecure is nil") - errPSKNil = ipnet.NewError("pre-shread key is nil") + errShortNonce = pnet.NewError("could not read full nonce") + errInsecureNil = pnet.NewError("insecure is nil") + errPSKNil = pnet.NewError("pre-shread key is nil") ) type pskConn struct { From a7b7b60b5d9a3c01607ab9915c4591ff9c95db43 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Thu, 20 Feb 2020 12:06:32 +0700 Subject: [PATCH 31/32] remove key serialization, construct conn from ipnet.PSK --- p2p/net/pnet/codec.go | 66 ----------------- p2p/net/pnet/codec_test.go | 123 ------------------------------- p2p/net/pnet/fingerprint.go | 24 ------ p2p/net/pnet/fingerprint_test.go | 18 ----- p2p/net/pnet/generate.go | 38 ---------- p2p/net/pnet/generate_test.go | 55 -------------- p2p/net/pnet/protector.go | 39 ++-------- p2p/net/pnet/psk_conn_test.go | 7 +- 8 files changed, 11 insertions(+), 359 deletions(-) delete mode 100644 p2p/net/pnet/codec.go delete mode 100644 p2p/net/pnet/codec_test.go delete mode 100644 p2p/net/pnet/fingerprint.go delete mode 100644 p2p/net/pnet/fingerprint_test.go delete mode 100644 p2p/net/pnet/generate.go delete mode 100644 p2p/net/pnet/generate_test.go diff --git a/p2p/net/pnet/codec.go b/p2p/net/pnet/codec.go deleted file mode 100644 index 19b929f6..00000000 --- a/p2p/net/pnet/codec.go +++ /dev/null @@ -1,66 +0,0 @@ -package pnet - -import ( - "bufio" - "bytes" - "encoding/base64" - "encoding/hex" - "fmt" - "io" -) - -var ( - pathPSKv1 = []byte("/key/swarm/psk/1.0.0/") - pathBin = "/bin/" - pathBase16 = "/base16/" - pathBase64 = "/base64/" -) - -func readHeader(r *bufio.Reader) ([]byte, error) { - header, err := r.ReadBytes('\n') - if err != nil { - return nil, err - } - - return bytes.TrimRight(header, "\r\n"), nil -} - -func expectHeader(r *bufio.Reader, expected []byte) error { - header, err := readHeader(r) - if err != nil { - return err - } - if !bytes.Equal(header, expected) { - return fmt.Errorf("expected file header %s, got: %s", pathPSKv1, header) - } - return nil -} - -func decodeV1PSK(in io.Reader) (*[32]byte, error) { - reader := bufio.NewReader(in) - if err := expectHeader(reader, pathPSKv1); err != nil { - return nil, err - } - header, err := readHeader(reader) - if err != nil { - return nil, err - } - - var decoder io.Reader - switch string(header) { - case pathBase16: - decoder = hex.NewDecoder(reader) - case pathBase64: - decoder = base64.NewDecoder(base64.StdEncoding, reader) - case pathBin: - decoder = reader - default: - return nil, fmt.Errorf("unknown encoding: %s", header) - } - out := new([32]byte) - _, err = io.ReadFull(decoder, out[:]) - if err != nil { - return nil, err - } - return out, nil -} diff --git a/p2p/net/pnet/codec_test.go b/p2p/net/pnet/codec_test.go deleted file mode 100644 index 233f3419..00000000 --- a/p2p/net/pnet/codec_test.go +++ /dev/null @@ -1,123 +0,0 @@ -package pnet - -import ( - "bytes" - "encoding/base64" - "testing" -) - -func bufWithBase(base string, windows bool) *bytes.Buffer { - - b := &bytes.Buffer{} - b.Write(pathPSKv1) - if windows { - b.WriteString("\r") - } - b.WriteString("\n") - b.WriteString(base) - if windows { - b.WriteString("\r") - } - b.WriteString("\n") - return b -} - -func TestDecodeHex(t *testing.T) { - testDecodeHex(t, true) - testDecodeHex(t, false) -} - -func TestDecodeBad(t *testing.T) { - testDecodeBad(t, true) - testDecodeBad(t, false) -} - -func testDecodeBad(t *testing.T, windows bool) { - b := bufWithBase("/verybadbase/", windows) - b.WriteString("Have fun decoding that key") - - _, err := decodeV1PSK(b) - if err == nil { - t.Fatal("expected 'unknown encoding' got nil") - } -} - -func testDecodeHex(t *testing.T, windows bool) { - b := bufWithBase("/base16/", windows) - for i := 0; i < 32; i++ { - b.WriteString("FF") - } - - psk, err := decodeV1PSK(b) - if err != nil { - t.Fatal(err) - } - - for _, b := range psk { - if b != 255 { - t.Fatal("byte was wrong") - } - } -} - -func TestDecodeB64(t *testing.T) { - testDecodeB64(t, true) - testDecodeB64(t, false) -} - -func testDecodeB64(t *testing.T, windows bool) { - b := bufWithBase("/base64/", windows) - key := make([]byte, 32) - for i := 0; i < 32; i++ { - key[i] = byte(i) - } - - e := base64.NewEncoder(base64.StdEncoding, b) - _, err := e.Write(key) - if err != nil { - t.Fatal(err) - } - err = e.Close() - if err != nil { - t.Fatal(err) - } - - psk, err := decodeV1PSK(b) - if err != nil { - t.Fatal(err) - } - - for i, b := range psk { - if b != psk[i] { - t.Fatal("byte was wrong") - } - } - -} - -func TestDecodeBin(t *testing.T) { - testDecodeBin(t, true) - testDecodeBin(t, false) -} - -func testDecodeBin(t *testing.T, windows bool) { - b := bufWithBase("/bin/", windows) - key := make([]byte, 32) - for i := 0; i < 32; i++ { - key[i] = byte(i) - } - - b.Write(key) - - psk, err := decodeV1PSK(b) - if err != nil { - t.Fatal(err) - } - - for i, b := range psk { - if b != psk[i] { - t.Fatal("byte was wrong") - } - } - -} diff --git a/p2p/net/pnet/fingerprint.go b/p2p/net/pnet/fingerprint.go deleted file mode 100644 index 978a46b6..00000000 --- a/p2p/net/pnet/fingerprint.go +++ /dev/null @@ -1,24 +0,0 @@ -package pnet - -import ( - "golang.org/x/crypto/salsa20" - "golang.org/x/crypto/sha3" -) - -var zero64 = make([]byte, 64) - -func fingerprint(psk *[32]byte) []byte { - enc := make([]byte, 64) - - // We encrypt data first so we don't feed PSK to hash function. - // Salsa20 function is not reversible thus increasing our security margin. - salsa20.XORKeyStream(enc, zero64, []byte("finprint"), psk) - - out := make([]byte, 16) - // Then do Shake-128 hash to reduce its length. - // This way if for some reason Shake is broken and Salsa20 preimage is possible, - // attacker has only half of the bytes necessary to recreate psk. - sha3.ShakeSum128(out, enc) - - return out -} diff --git a/p2p/net/pnet/fingerprint_test.go b/p2p/net/pnet/fingerprint_test.go deleted file mode 100644 index 04b238e6..00000000 --- a/p2p/net/pnet/fingerprint_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package pnet - -import ( - "bytes" - "testing" -) - -var tpsk *[32]byte = &[32]byte{} - -func TestFingerprintGen(t *testing.T) { - f := fingerprint(tpsk) - exp := []byte{0x70, 0x8a, 0x75, 0xaf, 0xd0, 0x5a, 0xff, 0xb0, 0x87, 0x36, 0xcb, 0xf1, 0x7c, 0x73, 0x77, 0x3e} - - if !bytes.Equal(f, exp) { - t.Fatal("fingerprint different than expected") - } - -} diff --git a/p2p/net/pnet/generate.go b/p2p/net/pnet/generate.go deleted file mode 100644 index cf220ced..00000000 --- a/p2p/net/pnet/generate.go +++ /dev/null @@ -1,38 +0,0 @@ -package pnet - -import ( - "bytes" - "crypto/rand" - "encoding/hex" - "io" -) - -func newLine() io.Reader { - return bytes.NewReader([]byte("\n")) -} - -// GenerateV1PSK generates new PSK key that can be used with NewProtector -func GenerateV1PSK() (io.Reader, error) { - psk, err := GenerateV1Bytes() - if err != nil { - return nil, err - } - - hexPsk := make([]byte, len(psk)*2) - hex.Encode(hexPsk, psk[:]) - - // just a shortcut to NewReader - nr := func(b []byte) io.Reader { - return bytes.NewReader(b) - } - return io.MultiReader(nr(pathPSKv1), newLine(), nr([]byte("/base16/")), newLine(), nr(hexPsk)), nil -} - -func GenerateV1Bytes() (*[32]byte, error) { - psk := [32]byte{} - _, err := rand.Read(psk[:]) - if err != nil { - return nil, err - } - return &psk, nil -} diff --git a/p2p/net/pnet/generate_test.go b/p2p/net/pnet/generate_test.go deleted file mode 100644 index e06e4c1e..00000000 --- a/p2p/net/pnet/generate_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package pnet - -import ( - "bytes" - "io/ioutil" - "testing" -) - -func TestGeneratedPSKCanBeUsed(t *testing.T) { - psk, err := GenerateV1PSK() - if err != nil { - t.Fatal(err) - } - - _, err = NewProtector(psk) - if err != nil { - t.Fatal(err) - } -} - -func TestGeneratedKeysAreDifferent(t *testing.T) { - psk1, err := GenerateV1PSK() - if err != nil { - t.Fatal(err) - } - psk2, err := GenerateV1PSK() - if err != nil { - t.Fatal(err) - } - bpsk1, err := ioutil.ReadAll(psk1) - if err != nil { - t.Fatal(err) - } - bpsk2, err := ioutil.ReadAll(psk2) - if err != nil { - t.Fatal(err) - } - if bytes.Equal(bpsk1, bpsk2) { - t.Fatal("generated keys are the same") - } -} - -func TestGeneratedV1BytesAreDifferent(t *testing.T) { - b1, err := GenerateV1Bytes() - if err != nil { - t.Fatal(err) - } - b2, err := GenerateV1Bytes() - if err != nil { - t.Fatal(err) - } - if bytes.Equal(b1[:], b2[:]) { - t.Fatal("generated keys are the same") - } -} diff --git a/p2p/net/pnet/protector.go b/p2p/net/pnet/protector.go index 8b8d2dd0..ed63a690 100644 --- a/p2p/net/pnet/protector.go +++ b/p2p/net/pnet/protector.go @@ -1,41 +1,18 @@ package pnet import ( - "fmt" - "io" + "errors" "net" ipnet "github.com/libp2p/go-libp2p-core/pnet" ) -var _ ipnet.Protector = (*protector)(nil) - -// NewProtector creates ipnet.Protector instance from a io.Reader stream -// that should include Multicodec encoded V1 PSK. -func NewProtector(input io.Reader) (ipnet.Protector, error) { - psk, err := decodeV1PSK(input) - if err != nil { - return nil, fmt.Errorf("malformed private network key: %s", err) +// NewProtectedConn creates a new protected connection +func NewProtectedConn(psk ipnet.PSK, conn net.Conn) (net.Conn, error) { + if len(psk) != 32 { + return nil, errors.New("expected 32 byte PSK") } - return NewV1ProtectorFromBytes(psk) -} - -// NewV1ProtectorFromBytes creates ipnet.Protector of the V1 version. -func NewV1ProtectorFromBytes(psk *[32]byte) (ipnet.Protector, error) { - return &protector{ - psk: psk, - fingerprint: fingerprint(psk), - }, nil -} - -type protector struct { - psk *[32]byte - fingerprint []byte -} - -func (p protector) Protect(in net.Conn) (net.Conn, error) { - return newPSKConn(p.psk, in) -} -func (p protector) Fingerprint() []byte { - return p.fingerprint + var p [32]byte + copy(p[:], psk) + return newPSKConn(&p, conn) } diff --git a/p2p/net/pnet/psk_conn_test.go b/p2p/net/pnet/psk_conn_test.go index 23108f40..f807b183 100644 --- a/p2p/net/pnet/psk_conn_test.go +++ b/p2p/net/pnet/psk_conn_test.go @@ -8,16 +8,15 @@ import ( "testing" ) -var testPSK = [32]byte{} // null bytes are as good test key as any other key - func setupPSKConns(ctx context.Context, t *testing.T) (net.Conn, net.Conn) { + testPSK := make([]byte, 32) // null bytes are as good test key as any other key conn1, conn2 := net.Pipe() - psk1, err := newPSKConn(&testPSK, conn1) + psk1, err := NewProtectedConn(testPSK, conn1) if err != nil { t.Fatal(err) } - psk2, err := newPSKConn(&testPSK, conn2) + psk2, err := NewProtectedConn(testPSK, conn2) if err != nil { t.Fatal(err) } From 64e14f92a073b474fc7b1a4ced092ff95e9ee947 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Fri, 23 Apr 2021 10:59:42 +0700 Subject: [PATCH 32/32] fix staticcheck --- p2p/net/pnet/psk_conn_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/p2p/net/pnet/psk_conn_test.go b/p2p/net/pnet/psk_conn_test.go index f807b183..83280883 100644 --- a/p2p/net/pnet/psk_conn_test.go +++ b/p2p/net/pnet/psk_conn_test.go @@ -76,7 +76,9 @@ func TestPSKFragmentation(t *testing.T) { }() for i := 0; i < 10; i++ { - _, err = psk2.Read(out) + if _, err := psk2.Read(out); err != nil { + t.Fatal(err) + } if !bytes.Equal(in[:100], out) { t.Fatalf("input and output are not the same") }