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 ¶
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 ¶
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) Ready ¶
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) Rekey ¶
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.