func TestPingPong(t *testing.T) { // t.Parallel() logs.ResetLogger() withTwoEndpoints(t, func(A, B *Endpoint) { var ( assert = assert.New(t) c *Channel ident *Identity pkt *lob.Packet err error ) go func() { c, err := A.Listen("ping", false).AcceptChannel() c.SetDeadline(time.Now().Add(10 * time.Second)) if assert.NoError(err) && assert.NotNil(c) { defer c.Close() pkt, err = c.ReadPacket() if assert.NoError(err) && assert.NotNil(pkt) { assert.Equal("ping", string(pkt.Body(nil))) err = c.WritePacket(lob.New([]byte("pong"))) assert.NoError(err) } } }() ident, err = A.LocalIdentity() assert.NoError(err) c, err = B.Open(ident, "ping", false) assert.NoError(err) if assert.NotNil(c) { defer c.Close() c.SetDeadline(time.Now().Add(10 * time.Second)) err = c.WritePacket(lob.New([]byte("ping"))) assert.NoError(err) pkt, err = c.ReadPacket() if assert.NoError(err) && assert.NotNil(pkt) { assert.Equal("pong", string(pkt.Body(nil))) } } }) }
func (mod *module) introduceVia(router *e3x.Exchange, to hashname.H) error { localIdent, err := mod.e.LocalIdentity() if err != nil { return err } keys := localIdent.Keys() parts := hashname.PartsFromKeys(keys) for csid, key := range keys { inner := lob.New(key.Public()) for partCSID, part := range parts { if partCSID == csid { inner.Header().SetBool(hex.EncodeToString([]byte{partCSID}), true) } else { inner.Header().SetString(hex.EncodeToString([]byte{partCSID}), part) } } body, err := lob.Encode(inner) if err != nil { return err } err = mod.peerVia(router, to, body) if err != nil { return err } } return nil }
func (s *state) EncryptHandshake(at uint32, compact cipherset.Parts) ([]byte, error) { pkt := lob.New(s.localKey.Public()) compact.ApplyToHeader(pkt.Header()) pkt.Header().SetUint32("at", at) data, err := lob.Encode(pkt) if err != nil { return nil, err } return s.EncryptMessage(data.Get(nil)) }
// Write implements the net.Conn Write method. func (c *Channel) Write(b []byte) (int, error) { n := len(b) pkt := lob.New(b) err := c.WritePacket(pkt) if err != nil { return 0, err } return n, nil }
func (s *state) EncryptPacket(pkt *lob.Packet) (*lob.Packet, error) { s.mtx.RLock() defer s.mtx.RUnlock() var ( outer *lob.Packet inner *bufpool.Buffer body *bufpool.Buffer bodyRaw []byte nonce [lenNonce]byte ctLen int err error ) if !s.CanEncryptPacket() { return nil, cipherset.ErrInvalidState } if pkt == nil { return nil, nil } // encode inner packet inner, err = lob.Encode(pkt) if err != nil { return nil, err } // make nonce copy(nonce[:], s.pktNoncePrefix[:]) nonceSuffix := atomic.AddUint64(&s.pktNonceSuffix, 1) binary.BigEndian.PutUint64(nonce[16:], nonceSuffix) // alloc enough space body = bufpool.New().SetLen(lenToken + lenNonce + inner.Len() + box.Overhead) bodyRaw = body.RawBytes() // copy token copy(bodyRaw[:lenToken], s.remoteToken[:]) // copy nonce copy(bodyRaw[lenToken:lenToken+lenNonce], nonce[:]) // encrypt inner packet ctLen = len(box.SealAfterPrecomputation( bodyRaw[lenToken+lenNonce:lenToken+lenNonce], inner.RawBytes(), &nonce, s.lineEncryptionKey)) body.SetLen(lenToken + lenNonce + ctLen) outer = lob.New(body.RawBytes()) inner.Free() body.Free() return outer, nil }
func (mod *module) peerVia(router *e3x.Exchange, to hashname.H, body *bufpool.Buffer) error { ch, err := router.Open("peer", false) if err != nil { return err } defer ch.Kill() pkt := lob.New(body.RawBytes()) pkt.Header().SetString("peer", string(to)) ch.WritePacket(pkt) return nil }
func (c *connection) sendHandshake(body []byte) error { ch, err := c.ex.Open("peer", false) if err != nil { return err } // defer e3x.ForgetterFromEndpoint(c.ex.).ForgetChannel(ch) pkt := lob.New(body) pkt.Header().SetString("peer", string(c.target)) ch.WritePacket(pkt) return nil }
func (mod *module) connect(ex *e3x.Exchange, inner *bufpool.Buffer) error { ch, err := ex.Open("connect", false) if err != nil { return err } defer ch.Kill() err = ch.WritePacket(lob.New(inner.RawBytes())) if err != nil { return err } return nil }
func (s *state) EncryptPacket(pkt *lob.Packet) (*lob.Packet, error) { s.mtx.RLock() defer s.mtx.RUnlock() var ( outer *lob.Packet inner *bufpool.Buffer body *bufpool.Buffer bodyRaw []byte nonce [16]byte ctLen int err error ) if !s.CanEncryptPacket() { return nil, cipherset.ErrInvalidState } if pkt == nil { return nil, nil } // encode inner packet inner, err = lob.Encode(pkt) if err != nil { return nil, err } ctLen = inner.Len() // make nonce _, err = io.ReadFull(rand.Reader, nonce[:4]) if err != nil { return nil, err } // alloc enough space body = bufpool.New().SetLen(16 + 4 + ctLen + 4) bodyRaw = body.RawBytes() // copy token copy(bodyRaw[:16], (*s.remoteToken)[:]) // copy nonce copy(bodyRaw[16:16+4], nonce[:]) { // encrypt inner aesBlock, err := aes.NewCipher(s.lineEncryptionKey) if err != nil { return nil, err } aes := Cipher.NewCTR(aesBlock, nonce[:]) if aes == nil { return nil, cipherset.ErrInvalidMessage } aes.XORKeyStream(bodyRaw[16+4:16+4+ctLen], inner.RawBytes()) } { // compute HMAC macKey := append(s.lineEncryptionKey, bodyRaw[16:16+4]...) h := hmac.New(sha256.New, macKey) h.Write(bodyRaw[16+4 : 16+4+ctLen]) sum := h.Sum(nil) copy(bodyRaw[16+4+ctLen:], fold(sum, 4)) } outer = lob.New(body.RawBytes()) inner.Free() body.Free() return outer, nil }
func BenchmarkPacketDecryption(b *testing.B, c cipherset.Cipher) { pkt := lob.New(bytes.Repeat([]byte{'x'}, 1024)) lkey, err := c.GenerateKey() if err != nil { b.Fatal(err) } rkey, err := c.GenerateKey() if err != nil { b.Fatal(err) } lstate, err := c.NewState(lkey) if err != nil { b.Fatal(err) } rstate, err := c.NewState(rkey) if err != nil { b.Fatal(err) } err = lstate.SetRemoteKey(rkey) if err != nil { b.Fatal(err) } hs, err := lstate.EncryptHandshake(1, nil) if err != nil { b.Fatal(err) } hsMsg, err := c.DecryptHandshake(rkey, hs) if err != nil { b.Fatal(err) } ok := rstate.ApplyHandshake(hsMsg) if !ok { b.Fatal("handshake failed") } hs, err = rstate.EncryptHandshake(1, nil) if err != nil { b.Fatal(err) } hsMsg, err = c.DecryptHandshake(lkey, hs) if err != nil { b.Fatal(err) } ok = lstate.ApplyHandshake(hsMsg) if !ok { b.Fatal("handshake failed") } pkt, err = rstate.EncryptPacket(pkt) if err != nil { b.Fatal(err) } b.SetBytes(1024) b.ResetTimer() for i := 0; i < b.N; i++ { epkt, err := lstate.DecryptPacket(pkt) epkt.Free() if err != nil { b.Fatal(err) } } }
func (s *cipherTestSuite) TestPacketEncryption() { var ( assert = s.Assertions c = s.cipher ) var ( ka cipherset.Key kb cipherset.Key sa cipherset.State sb cipherset.State ha cipherset.Handshake hb cipherset.Handshake pkt *lob.Packet box []byte err error ok bool ) ka, err = c.GenerateKey() assert.NoError(err) kb, err = c.GenerateKey() assert.NoError(err) sa, err = c.NewState(ka) assert.NoError(err) sb, err = c.NewState(kb) assert.NoError(err) err = sa.SetRemoteKey(kb) assert.NoError(err) box, err = sa.EncryptHandshake(1, nil) assert.NoError(err) hb, err = c.DecryptHandshake(kb, box) assert.NoError(err) ok = sb.ApplyHandshake(hb) assert.True(ok) box, err = sb.EncryptHandshake(1, nil) assert.NoError(err) ha, err = c.DecryptHandshake(ka, box) assert.NoError(err) ok = sa.ApplyHandshake(ha) assert.True(ok) pkt = lob.New([]byte("Hello world!")) pkt.Header().SetInt("foo", 0xbeaf) pkt, err = sa.EncryptPacket(pkt) assert.NoError(err) assert.NotNil(pkt) assert.Nil(pkt.Header().Bytes) assert.True(pkt.Header().IsZero()) assert.NotEmpty(pkt.Body) pkt, err = sb.DecryptPacket(pkt) assert.NoError(err) assert.NotNil(pkt) assert.Nil(pkt.Header().Bytes) assert.Equal(&lob.Header{Extra: map[string]interface{}{"foo": 0xbeaf}}, pkt.Header()) assert.Equal([]byte("Hello world!"), pkt.Body(nil)) pkt = lob.New([]byte("Bye world!")) pkt.Header().SetInt("bar", 0xdead) pkt, err = sb.EncryptPacket(pkt) assert.NoError(err) assert.NotNil(pkt) assert.Nil(pkt.Header().Bytes) assert.True(pkt.Header().IsZero()) assert.NotEmpty(pkt.Body) pkt, err = sa.DecryptPacket(pkt) assert.NoError(err) assert.NotNil(pkt) assert.Nil(pkt.Header().Bytes) assert.Equal(&lob.Header{Extra: map[string]interface{}{"bar": 0xdead}}, pkt.Header()) assert.Equal([]byte("Bye world!"), pkt.Body(nil)) }
func BenchmarkChannelsReliable(b *testing.B) { defer dumpExpVar(b) logs.ResetLogger() var ( ping = []byte("ping") pong = []byte("pong") ) client := func(x *Exchange) { c, err := x.Open("ping", true) if err != nil { b.Fatal(err) } defer c.Close() pkt := lob.New(ping) err = c.WritePacket(pkt) if err != nil { b.Fatal(err) } pkt, err = c.ReadPacket() if err != nil { b.Fatal(err) } pkt.Free() } server := func(c *Channel) { defer c.Close() pkt, err := c.ReadPacket() if err != nil { b.Fatal(err) } pkt.Free() pkt = lob.New(pong) err = c.WritePacket(pkt) if err != nil { b.Fatal(err) } } accept := func(l *Listener) { for { c, err := l.AcceptChannel() if err == io.EOF { break } if err != nil { b.Fatal(err) } go server(c) } } withTwoEndpoints(b, func(A, B *Endpoint) { A.setOptions(DisableLog()) B.setOptions(DisableLog()) var ( ident *Identity err error ) b.ResetTimer() l := A.Listen("ping", true) defer l.Close() go accept(l) ident, err = A.LocalIdentity() if err != nil { b.Fatal(err) } x, err := B.Dial(ident) if err != nil { b.Fatal(err) } b.ResetTimer() for i := 0; i < b.N; i++ { client(x) } b.StopTimer() }) }
func BenchmarkReadWriteUnreliable(b *testing.B) { defer dumpExpVar(b) logs.ResetLogger() withTwoEndpoints(b, func(A, B *Endpoint) { A.setOptions(DisableLog()) B.setOptions(DisableLog()) var ( c *Channel ident *Identity pkt *lob.Packet err error body = bytes.Repeat([]byte{'x'}, 1300) ) b.SetBytes(int64(len(body))) b.ResetTimer() go func() { c, err := A.Listen("flood", false).AcceptChannel() if err != nil { b.Fatal(err) } defer c.Close() pkt, err = c.ReadPacket() if err != nil { b.Fatal(err) } for i := 0; i < b.N; i++ { pkt := lob.New(body) err = c.WritePacket(pkt) if err != nil { b.Fatal(err) } // Give the other go routines some room to breath when GOMAXPROCS=1 runtime.Gosched() } }() ident, err = A.LocalIdentity() if err != nil { b.Fatal(err) } c, err = B.Open(ident, "flood", false) if err != nil { b.Fatal(err) } defer c.Close() err = c.WritePacket(lob.New(nil)) if err != nil { b.Fatal(err) } for { pkt, err = c.ReadPacket() if err == io.EOF { break } if err != nil { b.Fatal(err) } pkt.Free() } b.StopTimer() }) }
func TestFloodReliable(t *testing.T) { if testing.Short() { t.Skip("this is a long running test.") } withTwoEndpoints(t, func(A, B *Endpoint) { A.setOptions(DisableLog()) B.setOptions(DisableLog()) var ( assert = assert.New(t) c *Channel ident *Identity pkt *lob.Packet err error ) go func() { c, err := A.Listen("flood", true).AcceptChannel() if assert.NoError(err) && assert.NotNil(c) { defer c.Close() pkt, err = c.ReadPacket() assert.NoError(err) assert.NotNil(pkt) for i := 0; i < 100000; i++ { pkt := lob.New(nil) pkt.Header().SetInt("flood_id", i) err = c.WritePacket(pkt) assert.NoError(err) } } }() ident, err = A.LocalIdentity() assert.NoError(err) c, err = B.Open(ident, "flood", true) assert.NoError(err) assert.NotNil(c) defer c.Close() err = c.WritePacket(lob.New(nil)) assert.NoError(err) lastID := -1 for { pkt, err = c.ReadPacket() if err == io.EOF { break } assert.NoError(err) assert.NotNil(pkt) if err != nil { break } if pkt != nil { id, _ := pkt.Header().GetInt("flood_id") assert.True(lastID < id) lastID = id } } }) }