schannel

package
v0.0.0-...-ef8e705 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 12, 2015 License: ISC Imports: 7 Imported by: 1

Documentation

Overview

Package schannel establishes bidirectional secure channels over TCP/IP.

This package is a port of libschannel (https://github.com/kisom/libschannel) to Go. For details on the protocol and the properties of a secure channel, the libschannel documentation should be consulted. Secure channels use Curve25519 ECDH to exchange NaCl secretbox keys, and Ed25519 to sign key exchanges.

A secure channel is established with the Dial and Listen functions: one side called Dial to set up a key exchange with the other side, and the other side calls Listen to finalise the key exchange. For example, the client might have the following:

conn, err := net.Dial("tcp", host)
die.If(err)
defer conn.Close()

sch, ok := schannel.Dial(conn, idPriv, idPeer)
if !ok {
	die.With("failed to set up secure channel")
}
fmt.Println("secure channel established")

On the server side, the code might look like this:

ln, err := net.Listen("tcp", ":"+port)
die.If(err)

fmt.Println("Listening on", ":"+port)
for {
	conn, err := ln.Accept()
	if err != nil {
		fmt.Printf("Connection error: %v\n", err)
		continue
	}
	sch, ok := schannel.Listen(conn, idPriv, idPeer)
	if !ok {
		log.Printf("failed to establish secure channel")
	}
	log.Printf("secure channel established")
	go run session(sch)
}

Authentication is done using identity signature keys. These keys must be known ahead of time, and key distribution is not a part of this library. Each side chooses whether to sign and/or verify the signature on the key exchange by providing an appropriate key or a nil key.

The two pairs may send messages over the secure channel using the Send function. These messages may be received with the Receive function, which returns a *Message that pairs the message type with the message contents.

If the message is a NormalMessage, the contents will contain the original message that was sent. If it is a KEXMessage or ShutdownMessage, the contents will be empty. In the case of a KEXMessage, the receiver does not need to do anything: it indicates that a key rotation took place, and is provided for informational purposes. However, if the message is a ShutdownMessage, the receiver should call the Zero method on the secure channel.

Index

Constants

View Source
const (
	// BufSize is the maximum size of an encrypted message.
	BufSize = 2097152 // 2MiB: 2 * 1024 * 1024B

	// IdentityPrivateSize is the size of an identity private key.
	IdentityPrivateSize = ed25519.PrivateKeySize

	// IdentityPublicSize is the size of an identity public key.
	IdentityPublicSize = ed25519.PublicKeySize

	// KeySize is the size of a shared encryption key.
	KeySize = 32

	// Overhead is the amount of overhead added to a message
	// when it is encrypted. This is the size of a nonce, MAC,
	// and message envelope.
	Overhead = 106

	// SignatureSize is the length of an identity signature.
	SignatureSize = ed25519.SignatureSize
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Channel

type Channel io.ReadWriter

A Channel is an insecure channel; a secure channel is overlaid on top of this channel.

type Message

type Message struct {
	Type     MessageType
	Contents []byte
}

Message pairs a message type with contents.

type MessageType

type MessageType uint8

A MessageType represents a type of message.

const (
	// InvalidMessage is any message that is invalid.
	InvalidMessage MessageType = iota

	// NormalMessage is a normal message.
	NormalMessage

	// KEXMessage is a key exchange message.
	KEXMessage

	// ShutdownMessage is an indication that the secure channel
	// should be shut down.
	ShutdownMessage
)

type SChannel

type SChannel struct {
	// RData and SData store the amount of data decrypted (received)
	// and encrypted (sent), respectively.
	RData uint64
	SData uint64

	// Channel is the insecure channel the SChannel is built on.
	Channel Channel
	// contains filtered or unexported fields
}

An SChannel is a secure channel. It contains separate encryption keys for receiving and sending messages, and tracks message numbers to prevent forgeries.

func Dial

func Dial(ch Channel, signer *[IdentityPrivateSize]byte, peer *[IdentityPublicSize]byte) (*SChannel, bool)

Dial initialise the SChannel and initiate a key exchange over the Channel. If this returns true, an authenticated secure channel has been established. If signer is not nil, the key exchange will be signed with the key it contains. If peer is not nil, the key exchange will be verified using the public key it contains.

func Listen

func Listen(ch Channel, signer *[IdentityPrivateSize]byte, peer *[IdentityPublicSize]byte) (*SChannel, bool)

Listen initialises the SChannel and complete a key exchange over the Channel. If this returns true, an authenticated secure channel has been established. If signer is not nil, the key exchange will be signed with the key it contains. If peer is not nil, the key exchange will be verified using the public key it contains.

func (*SChannel) Close

func (sch *SChannel) Close() bool

Close signals the other end of the secure channel that the channel is being closed, and calls Zero to zeroise the secure channel. After this, the caller should close the underlying channel as appropriate.

func (*SChannel) RCtr

func (sch *SChannel) RCtr() uint32

RCtr returns the last received message counter.

func (*SChannel) Ready

func (sch *SChannel) Ready() bool

Ready returns true if the secure channel is ready to send or receive messages. If it returns false, the secure channel should be zeroised and discarded.

func (*SChannel) Receive

func (sch *SChannel) Receive() (*Message, bool)

Receive reads a new message from the secure channel.

func (*SChannel) Rekey

func (sch *SChannel) Rekey() bool

Rekey initiates a key rotation with the other side. Both sides will generate new session private keys, and exchange their public halves. These session keys will not be signed, as the channel is assumed to be authenticated and secure at this point. Generally, key rotation will not be an issue. However, peers may elect to rekey after a certain time period, a certain number of messages have been sent, or a certain amount of data will be sent.

func (*SChannel) SCtr

func (sch *SChannel) SCtr() uint32

SCtr returns the last sent message counter.

func (*SChannel) Send

func (sch *SChannel) Send(m []byte) bool

Send seals the message and sends it over the secure channel.

func (*SChannel) Zero

func (sch *SChannel) Zero()

Zero zeroises the channel, wiping the shared keys from memory and resetting the channel. After this is called, the secure channel cannot be used for anything else.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL