Example #1
0
// Tests whether link ciphers are initializes correctly.
func TestCiphers(t *testing.T) {
	t.Parallel()

	// Generate a secret key for the HKDF
	secret := make([]byte, 16)
	io.ReadFull(rand.Reader, secret)

	// Create the server and client links (no connection between them)
	clientHKDF := hkdf.New(sha1.New, secret, []byte("HKDF salt"), []byte("HKDF info"))
	serverHKDF := hkdf.New(sha1.New, secret, []byte("HKDF salt"), []byte("HKDF info"))

	client := New(nil, clientHKDF, false)
	server := New(nil, serverHKDF, true)

	// Create some random data to operate on
	clientData := make([]byte, 4096)
	serverData := make([]byte, 4096)

	io.ReadFull(rand.Reader, clientData)
	copy(serverData, clientData)

	// Check that encryption and MACing match on the two sides
	for i := 0; i < 1000; i++ {
		client.inCipher.XORKeyStream(clientData, clientData)
		server.outCipher.XORKeyStream(serverData, serverData)
		if !bytes.Equal(clientData, serverData) {
			t.Fatalf("cipher mismatch on the session endpoints")
		}
		client.outCipher.XORKeyStream(clientData, clientData)
		server.inCipher.XORKeyStream(serverData, serverData)
		if !bytes.Equal(clientData, serverData) {
			t.Fatalf("cipher mismatch on the session endpoints")
		}
		client.inMacer.Write(clientData)
		server.outMacer.Write(serverData)
		clientData = client.inMacer.Sum(nil)
		serverData = server.outMacer.Sum(nil)
		if !bytes.Equal(clientData, serverData) {
			t.Fatalf("macer mismatch on the session endpoints")
		}
		client.outMacer.Write(clientData)
		server.inMacer.Write(serverData)
		clientData = client.outMacer.Sum(nil)
		serverData = server.inMacer.Sum(nil)
		if !bytes.Equal(clientData, serverData) {
			t.Fatalf("macer mismatch on the session endpoints")
		}
	}
}
Example #2
0
// Initializes a stream into an encrypted tunnel link.
func (c *Connection) initClientTunnel(strm *stream.Stream, remote uint64, id uint64, key []byte, deadline time.Time) (*link.Link, error) {
	// Set a socket deadline for finishing the handshake
	strm.Sock().SetDeadline(deadline)
	defer strm.Sock().SetDeadline(time.Time{})

	// Send the unencrypted tunnel id to associate with the remote tunnel
	init := &initPacket{ConnId: remote, TunId: id}
	if err := strm.Send(init); err != nil {
		return nil, err
	}
	// Create the encrypted link and authorize it
	hasher := func() hash.Hash { return config.HkdfHash.New() }
	hkdf := hkdf.New(hasher, key, config.HkdfSalt, config.HkdfInfo)
	conn := link.New(strm, hkdf, false)

	// Send and retrieve an authorization to verify both directions
	auth := &proto.Message{
		Head: proto.Header{
			Meta: &authPacket{Id: id},
		},
	}
	if err := conn.SendDirect(auth); err != nil {
		return nil, err
	}
	if msg, err := conn.RecvDirect(); err != nil {
		return nil, err
	} else if auth, ok := msg.Head.Meta.(*authPacket); !ok || auth.Id != id {
		return nil, errors.New("protocol violation")
	}
	conn.Start(config.IrisTunnelBuffer)

	// Return the initialized link
	return conn, nil
}
Example #3
0
// Extracts a usable sized symmetric key and IV for the stream cipher from the huge master key, and
// creates a CTR stream cipher.
func (s *Session) makeCipher() (cipher.Stream, error) {
	// Create the key derivation function
	hasher := func() hash.Hash { return s.hash.New() }
	hkdf := hkdf.New(hasher, s.secret.Bytes(), hkdfSalt, hkdfInfo)

	// Extract the symmetric key
	key := make([]byte, s.keybits/8)
	n, err := io.ReadFull(hkdf, key)
	if n != len(key) || err != nil {
		return nil, err
	}
	// Create the block cipher
	block, err := s.crypter(key)
	if err != nil {
		return nil, err
	}
	// Extract the IV for the counter mode
	iv := make([]byte, block.BlockSize())
	n, err = io.ReadFull(hkdf, iv)
	if n != len(iv) || err != nil {
		return nil, err
	}
	// Create the stream cipher
	return cipher.NewCTR(block, iv), nil
}
Example #4
0
// Creates a new, double link session for authenticated data transfer. The
// initiator is used to decide the key derivation order for the channels.
func newSession(conn *stream.Stream, secret []byte, server bool) *Session {
	// Create the key derivation function
	hasher := func() hash.Hash { return config.HkdfHash.New() }
	hkdf := hkdf.New(hasher, secret, config.HkdfSalt, config.HkdfInfo)

	// Create the encrypted control link
	return &Session{
		kdf:      hkdf,
		CtrlLink: link.New(conn, hkdf, server),
	}
}
Example #5
0
// Initializes a stream into an encrypted tunnel link.
func (o *Overlay) initServerTunnel(strm *stream.Stream) error {
	// Set a socket deadline for finishing the handshake
	strm.Sock().SetDeadline(time.Now().Add(config.IrisTunnelInitTimeout))
	defer strm.Sock().SetDeadline(time.Time{})

	// Fetch the unencrypted client initiator
	init := new(initPacket)
	if err := strm.Recv(init); err != nil {
		return err
	}
	o.lock.RLock()
	c, ok := o.conns[init.ConnId]
	o.lock.RUnlock()
	if !ok {
		return errors.New("connection not found")
	}
	c.tunLock.RLock()
	tun, ok := c.tunLive[init.TunId]
	c.tunLock.RUnlock()
	if !ok {
		return errors.New("tunnel not found")
	}
	// Create the encrypted link
	hasher := func() hash.Hash { return config.HkdfHash.New() }
	hkdf := hkdf.New(hasher, tun.secret, config.HkdfSalt, config.HkdfInfo)
	conn := link.New(strm, hkdf, true)

	// Send and retrieve an authorization to verify both directions
	auth := &proto.Message{
		Head: proto.Header{
			Meta: &authPacket{Id: tun.id},
		},
	}
	if err := conn.SendDirect(auth); err != nil {
		return err
	}
	if msg, err := conn.RecvDirect(); err != nil {
		return err
	} else if auth, ok := msg.Head.Meta.(*authPacket); !ok || auth.Id != tun.id {
		return errors.New("protocol violation")
	}
	conn.Start(config.IrisTunnelBuffer)

	// Send back the initialized link to the pending tunnel
	select {
	case tun.init <- conn:
		// Connection handled by initiator
		return nil
	default:
		// Initiator timed out or terminated, close
		conn.Close()
		return nil // No error, since tunnel was handled, albeit not as expected
	}
}
Example #6
0
// Usage example that expands one master key into three other cryptographically
// secure keys.
func Example_usage() {
	// Underlying hash function to use
	hash := sha256.New

	// Cryptographically secure master key.
	master := []byte{0x00, 0x01, 0x02, 0x03} // i.e. NOT this.

	// Non secret salt, optional (can be nil)
	// Recommended: hash-length sized random
	salt := make([]byte, hash().Size())
	n, err := io.ReadFull(rand.Reader, salt)
	if n != len(salt) || err != nil {
		fmt.Println("error:", err)
		return
	}

	// Non secret context specific info, optional (can be nil).
	// Note, independent from the master key.
	info := []byte{0x03, 0x14, 0x15, 0x92, 0x65}

	// Create the key derivation function
	hkdf := hkdf.New(hash, master, salt, info)

	// Generate the required keys
	keys := make([][]byte, 3)
	for i := 0; i < len(keys); i++ {
		keys[i] = make([]byte, 24)
		n, err := io.ReadFull(hkdf, keys[i])
		if n != len(keys[i]) || err != nil {
			fmt.Println("error:", err)
			return
		}
	}

	// Keys should contain 192 bit random keys
	for i := 1; i <= len(keys); i++ {
		fmt.Printf("Key #%d: %v\n", i, !bytes.Equal(keys[i-1], make([]byte, 24)))
	}

	// Output:
	// Key #1: true
	// Key #2: true
	// Key #3: true
}
Example #7
0
// Tests the low level send and receive methods.
func TestDirectSendRecv(t *testing.T) {
	t.Parallel()

	// Start a stream listener
	addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
	if err != nil {
		t.Fatalf("failed to resolve local address: %v.", err)
	}
	listener, err := stream.Listen(addr)
	if err != nil {
		t.Fatalf("failed to listen for incoming streams: %v.", err)
	}
	listener.Accept(10 * time.Millisecond)
	defer listener.Close()

	// Establish a stream connection to the listener
	host := fmt.Sprintf("%s:%d", "localhost", addr.Port)
	clientStrm, err := stream.Dial(host, time.Millisecond)
	if err != nil {
		t.Fatalf("failed to connect to stream listener: %v.", err)
	}
	serverStrm := <-listener.Sink

	defer clientStrm.Close()
	defer serverStrm.Close()

	// Initialize the stream based encrypted links
	secret := make([]byte, 16)
	io.ReadFull(rand.Reader, secret)

	clientHKDF := hkdf.New(sha1.New, secret, []byte("HKDF salt"), []byte("HKDF info"))
	serverHKDF := hkdf.New(sha1.New, secret, []byte("HKDF salt"), []byte("HKDF info"))

	clientLink := New(clientStrm, clientHKDF, false)
	serverLink := New(serverStrm, serverHKDF, true)

	// Generate some random messages and pass around both ways
	for i := 0; i < 1000; i++ {
		// Generate the message to send
		send := &proto.Message{
			Head: proto.Header{
				Meta: make([]byte, 32),
			},
			Data: make([]byte, 32),
		}
		io.ReadFull(rand.Reader, send.Head.Meta.([]byte))
		io.ReadFull(rand.Reader, send.Data)
		send.Encrypt()

		// Send the message from client to server
		if err := clientLink.SendDirect(send); err != nil {
			t.Fatalf("failed to send message to server: %v.", err)
		}
		if recv, err := serverLink.RecvDirect(); err != nil {
			t.Fatalf("failed to receive message from client: %v.", err)
		} else if bytes.Compare(send.Head.Meta.([]byte), recv.Head.Meta.([]byte)) != 0 || bytes.Compare(send.Data, recv.Data) != 0 {
			t.Fatalf("send/receive mismatch: have %+v, want %+v.", recv, send)
		}
		// Send the message from server to client
		if err := serverLink.SendDirect(send); err != nil {
			t.Fatalf("failed to send message to client: %v.", err)
		}
		if recv, err := clientLink.RecvDirect(); err != nil {
			t.Fatalf("failed to receive message from server: %v.", err)
		} else if bytes.Compare(send.Head.Meta.([]byte), recv.Head.Meta.([]byte)) != 0 || bytes.Compare(send.Data, recv.Data) != 0 {
			t.Fatalf("send/receive mismatch: have %+v, want %+v.", recv, send)
		}
	}
}