canoe

package module
v0.0.0-...-ddd978e Latest Latest
Warning

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

Go to latest
Published: Mar 16, 2023 License: MIT Imports: 28 Imported by: 0

README

canoe

This protocol is much like a canoe: when used properly, it can be a fast, simple and secure mode of transport.

TODO

  • [] Add support for other key encoding formats (PPK, PKCS#8)
  • [] Add pubkey blacklisting on servers
  • [] Implement compression for packets

Documentation

Index

Constants

View Source
const (
	ErrNoPrivateKey    = bg.Error("no private key found")
	ErrInvalidResponse = bg.Error("invalid response from server")
	ErrWeakSessionkey  = bg.Error("weak session key")
)
View Source
const (
	ErrNoKeyFound        = bg.Error("no key found")
	ErrPassphraseMissing = bg.Error("this private key is passphrase protected")
	ErrNotEncryptedKey   = bg.Error("not an encrypted key")
	ErrUnsupportedKey    = bg.Error("unsupported key type")
)
View Source
const (
	ErrVersionMismatch  = bg.Error("protocol version mismatch")
	ErrWeakHandshakeKey = bg.Error("weak handshake key")
	ErrUnsupportedType  = bg.Error("unsupported transfer type")
	ErrFileTooLarge     = bg.Error("file size is too large")
)
View Source
const (
	ErrAlreadySubscribed = bg.Error("already subscribed to the queue")
)
View Source
const (
	ErrInvalidChecksum = bg.Error("invalid checksum")
)

Variables

This section is empty.

Functions

func CreateAESKey

func CreateAESKey() []byte

CreateAESKey creates a 256 bit encryption key

func DecryptAESGCM

func DecryptAESGCM(encryptedBytes, key []byte) ([]byte, error)

DecryptAESGCM will take ciphered data in bytes and an encryption key in bytes and decrypt the data using AES-GCM techniques

func DecryptOAEP

func DecryptOAEP(hash hash.Hash, random io.Reader, private *rsa.PrivateKey, msg []byte, label []byte) ([]byte, error)

DecryptOAEP is a wrapper function over the crypto/rsa package function of the same name It reconstructs longer messages from chunks

func EncryptAESGCM

func EncryptAESGCM(rawBytes, key []byte) ([]byte, error)

EncryptAESGCM takes raw bytes and an encryption key and encrypts the data using AES-GCM techniques

func EncryptOAEP

func EncryptOAEP(hash hash.Hash, random io.Reader, public *rsa.PublicKey, msg, label []byte) ([]byte, error)

EncryptOAEP is a wrapper function over the crypto/rsa package function of the same name It divides longer messages into chunks

func GetDirAvailableSpace

func GetDirAvailableSpace(dir string) (uint64, error)

GetDirAvailableSpace will check the available space within a specified directory

func ParsePrivateKey

func ParsePrivateKey(pemBytes []byte) (*rsa.PrivateKey, error)

ParsePrivateKey returns a private key from a PEM encoded private key. It only supports RSA. If the private key is encrypted, it will return an error

func ParsePrivateKeyWithPassphrase

func ParsePrivateKeyWithPassphrase(pemBytes []byte, passphrase []byte) (*rsa.PrivateKey, error)

ParsePrivateKeyWithPassphrase returns an RSA private key from a PEM encoded private key and passphrase.

func ParsePublicKey

func ParsePublicKey(pemBytes []byte) (*rsa.PublicKey, error)

ParsePublicKey will take a pem encoded RSA Public key and parse it

Types

type AckFrame

type AckFrame struct {
	Status  StatusTypes `json:"status"`  // OK or ERROR
	Payload []byte      `json:"payload"` // The specific ACK JSON object serialized if OK or an error message
}

func (AckFrame) Serialize

func (a AckFrame) Serialize() []byte

func (AckFrame) String

func (a AckFrame) String() string

type AckQueue

type AckQueue struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

func NewAckQueue

func NewAckQueue() *AckQueue

NewAckQueue creates an instance of the AckQueue

func (*AckQueue) Pop

func (q *AckQueue) Pop() uint32

Pop removes the first item in the queue and returns its value

func (*AckQueue) Push

func (q *AckQueue) Push(v int)

Push adds a new item to the queue

func (*AckQueue) Subscribe

func (q *AckQueue) Subscribe(name string) (chan int, func(), error)

Subscribe returns a channel which will have signals sent when a new item is pushed as well as an unsub function

type Client

type Client struct {
	Version uint8

	sync.WaitGroup
	// contains filtered or unexported fields
}

func Dial

func Dial(addr string, pubkey *rsa.PublicKey, config *ClientConfig) (*Client, error)

Dial starts a client connection to the given canoe server. It is a convenience function to the given network address initiates the Seif handshake, and then sets up a Client.

func (*Client) Close

func (c *Client) Close() error

Close ends the TCP connection

func (*Client) SendFile

func (c *Client) SendFile(pathToFile string) error

type ClientConfig

type ClientConfig struct {
	Rand io.Reader
	// contains filtered or unexported fields
}

func (*ClientConfig) AddHostKey

func (c *ClientConfig) AddHostKey(key *rsa.PrivateKey)

AddHostKey is a method for registering a private key in the server config

type Close

type Close struct{}

Encrypted with session key

func (Close) Serialize

func (c Close) Serialize() []byte

type Frame

type Frame struct {
	Type    MsgTypes `json:"type"`    // Indicator for msg receiver
	Payload string   `json:"payload"` // Encrypted and base64 encoded
}

What is sent over the wire TCP

func (Frame) Serialize

func (f Frame) Serialize() []byte

type HandshakeAck

type HandshakeAck struct {
	SessionKey []byte `json:"session_key"` // Server generated, symmetric key encrypted with client pubkey
	Signature  []byte `json:"signature"`   // Server signs the serialized and hashed version of this message with their private key
}

Message is encrypted with handshake key

func (HandshakeAck) Serialize

func (h HandshakeAck) Serialize() []byte

func (HandshakeAck) Sign

func (h HandshakeAck) Sign(privateKey *rsa.PrivateKey, rand io.Reader) ([]byte, error)

func (HandshakeAck) String

func (h HandshakeAck) String() string

type HandshakeInit

type HandshakeInit struct {
	Version      uint8  `json:"version"`       // Protocol version
	HandshakeKey []byte `json:"handshake_key"` // Client generated, symmetric key encrypted with servers pubkey
	Payload      []byte `json:"payload"`       // Clients pubkey encrypted with handshake key
	Signature    []byte `json:"signature"`     // Client signs the serialized and hashed version of this message with their private key
}

func (HandshakeInit) Serialize

func (h HandshakeInit) Serialize() []byte

func (HandshakeInit) Sign

func (h HandshakeInit) Sign(privateKey *rsa.PrivateKey, rand io.Reader) ([]byte, error)

func (HandshakeInit) String

func (h HandshakeInit) String() string

type MsgTypes

type MsgTypes uint8
const (
	HANDSHAKE_INIT MsgTypes = iota
	HANDSHAKE_ACK
	TRANSFER_INIT
	TRANSFER_ACK
	COMPLETE
	COMPLETE_ACK
	CLOSE
	PING
	PONG
	PACKET_ACK
)

type Packet

type Packet struct {
	OrderNumber uint32
	Data        []byte
	Checksum    uint64
}

Packet encrypted with session key, sent over UDP

func DecryptPacket

func DecryptPacket(p []byte, key []byte) (Packet, error)

DecryptPacket will take an encrypted packet, decrypt it and parse it

func (Packet) Serialize

func (p Packet) Serialize() []byte

type PacketAck

type PacketAck struct {
	OrderNumber uint32 `json:"order_numbers"`
}

func (PacketAck) Serialize

func (a PacketAck) Serialize() []byte

type PacketQueue

type PacketQueue struct {
	Queue []PacketQueueItem
	sync.RWMutex
}

func (*PacketQueue) Ack

func (q *PacketQueue) Ack(orderNumber int)

Ack changes the Acked status of a packet to true

func (*PacketQueue) CanSend

func (q *PacketQueue) CanSend(orderNumber int, timeout time.Duration) bool

CanSend determines if a given packet has timed out and if it hasn't already been acked by the server

func (*PacketQueue) IsAck

func (q *PacketQueue) IsAck(orderNumber int) bool

IsAck determines if a given packet was acked by the server

func (*PacketQueue) TimeSent

func (q *PacketQueue) TimeSent(orderNumber int, timeSent time.Time)

TimeSent updates the TimeSent parameter for a given packet

type PacketQueueItem

type PacketQueueItem struct {
	EncryptedPacket []byte
	Acked           bool
	TimeSent        time.Time
}

type Ping

type Ping struct{}

Encrypted with session key

func (Ping) Serialize

func (p Ping) Serialize() []byte

type Pong

type Pong struct{}

Encrypted with session key

func (Pong) Serialize

func (p Pong) Serialize() []byte

type PutFileTransferInit

type PutFileTransferInit struct {
	FileSize        uint64 `json:"file_size"`         // bytes
	FileName        string `json:"file_name"`         // filename.ext
	NumberOfPackets uint32 `json:"number_of_packets"` // total number of packets to be transfered
}

encrypted with session key

func (PutFileTransferInit) Serialize

func (t PutFileTransferInit) Serialize() []byte

func (PutFileTransferInit) String

func (t PutFileTransferInit) String() string

type QueueListener

type QueueListener struct {
	IsConnected bool
	Signal      chan int
}

type RcvPacketQueue

type RcvPacketQueue struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

func NewRcvPacketQueue

func NewRcvPacketQueue() *RcvPacketQueue

NewRcvPacketQueue instantiates a new ByteQueue struct

func (*RcvPacketQueue) Pop

func (q *RcvPacketQueue) Pop() Packet

Pop returns the first item in the queue and deletes it from the queue

func (*RcvPacketQueue) Push

func (q *RcvPacketQueue) Push(v Packet)

Push adds a new item to the back of the queue

func (*RcvPacketQueue) Subscribe

func (q *RcvPacketQueue) Subscribe(name string) (chan int, func(), error)

Subscribe returns a channel which will have signals sent when a new item is pushed as well as an unsub function

type Server

type Server struct {
	Version uint8
	// contains filtered or unexported fields
}

func NewServer

func NewServer(config *ServerConfig) *Server

NewServer creates a new instance of Server

func (*Server) Close

func (s *Server) Close() error

Close safely closes the server

func (*Server) Serve

func (s *Server) Serve(lis net.Listener) error

Serve creates a new go routine to start handling connection requests

type ServerConfig

type ServerConfig struct {
	Rand       io.Reader
	WorkingDir string
	// contains filtered or unexported fields
}

func (*ServerConfig) AddHostKey

func (s *ServerConfig) AddHostKey(key *rsa.PrivateKey)

AddHostKey is a method for registering a private key in the server config

type StatusTypes

type StatusTypes uint8
const (
	OK StatusTypes = iota
	ERROR
)

type TCPMsg

type TCPMsg interface {
	Serialize() []byte
}

type TransferAck

type TransferAck struct {
	UDPPort uint16 `json:"udp_port"` // Port that the server will listen on for UDP traffic
}

encrypted with session key

func (TransferAck) Serialize

func (t TransferAck) Serialize() []byte

type TransferComplete

type TransferComplete struct {
	PacketsToResend []uint32 `json:"packets_to_resend"` // array is empty if transfer is successful
}

Encrypted with session key

func (TransferComplete) Serialize

func (t TransferComplete) Serialize() []byte

type TransferCompleteAck

type TransferCompleteAck struct{}

Encrypted with session key

func (TransferCompleteAck) Serialize

func (t TransferCompleteAck) Serialize() []byte

type TransferFrame

type TransferFrame struct {
	Type    TransferTypes `json:"transfer_type"` // determines transfer type so server can properly handle the message
	Payload []byte        `json:"payload"`       // metadata about the particular transfer type
}

func (TransferFrame) Serialize

func (t TransferFrame) Serialize() []byte

func (TransferFrame) String

func (t TransferFrame) String() string

type TransferTypes

type TransferTypes uint8
const (
	PUT_FILE TransferTypes = iota // Can support other TransferTypes in the future
)

type UDPClient

type UDPClient struct {
	// contains filtered or unexported fields
}

func NewUDPClient

func NewUDPClient(host string, key []byte) (*UDPClient, error)

NewUDPClient will initialize the UDP client

func (*UDPClient) Buffer

func (c *UDPClient) Buffer() []byte

Buffer creates a new appropriately sized buffer

func (*UDPClient) Close

func (c *UDPClient) Close() error

Close will properly close the UDP client connection

type UDPServer

type UDPServer struct {
	// contains filtered or unexported fields
}

func NewUDPServer

func NewUDPServer(sessionKey []byte, numPackets uint32, workingDir string) *UDPServer

NewUDPServer instantiates a new UDPServer struct

func (*UDPServer) Close

func (u *UDPServer) Close() error

Close will close the underlying UDP connection

func (*UDPServer) ListenAndServe

func (u *UDPServer) ListenAndServe(port uint16, fileName string, q *AckQueue) error

ListenAndServe will create a UDP listener on the given port and spin up a goroutine to handle incoming connections

Directories

Path Synopsis
example

Jump to

Keyboard shortcuts

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