icy

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

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

Go to latest
Published: Mar 13, 2026 License: MIT Imports: 11 Imported by: 0

README

icy

icy (I-See-You) provides secure, authenticated streaming encryption. It uses a Noise handshake to establish symmetric keys, then encrypts all traffic with XChaCha20-Poly1305.

Installation

go get github.com/tetsuo/icy

Usage

// server
ln, _ := net.Listen("tcp", ":9000")
raw, _ := ln.Accept()
conn, err := icy.NewConn(false, raw, nil)

// client
raw, _ := net.Dial("tcp", "localhost:9000")
conn, err := icy.NewConn(true, raw, nil)

conn implements io.ReadWriteCloser. Each Write is framed and encrypted; each Read decrypts one frame. Frames are limited to 16 MB.

conn.Write([]byte("hello"))

buf := make([]byte, 4096)
n, err := conn.Read(buf)

For concurrent request/response pipelining, use Send + StartResponse/EndResponse:

id, err := conn.Send(payload) // thread-safe write, returns sequence id
conn.StartResponse(id)
n, err := conn.Read(buf)
conn.EndResponse(id)
Config
cfg := &icy.Config{
    Pattern:         noise.PatternXX, // default
    KeyPair:         kp,              // generated if nil
    RemotePublicKey: remotePub,       // required for IK/XK patterns
}
conn, err := icy.NewConn(true, raw, cfg)
Keys and handshake hash
conn.PublicKey()        // local static public key
conn.RemotePublicKey()  // remote static public key
conn.HandshakeHash()    // handshake hash, useful for channel binding

Wire format

[b0 b1 b2][ciphertext...]

3-byte little-endian length prefix, followed by the XChaCha20-Poly1305 ciphertext (plaintext + 16-byte tag).

CLI usage

icy command is an encrypted netcat clone for testing and ad-hoc file transfer. Install it with:

go install github.com/tetsuo/icy/cmd/icy@latest

Start a server:

icy -v -l 4242

Send some data:

printf 'Hello, world!\n' | icy -v localhost 4242

Server outputs:

listening on [::]:4242
local  e5dd025706a01f7608081c62121d67c28abcea65c079711a216600c55cc4df4c
remote dab0c97f5ab8252731dcc670aa63a298b3b032a6b8eafca0cd750cef36d47d26
hash   1eb97ba65a3508d312f67436ecc61e7971f1d290bc97bfa6b9e9c73cf2b195afeb9514669b176c212ee75a1837263c0abd5f41f42216749b31393738b664f4d7
Hello, world!

Client outputs:

local  dab0c97f5ab8252731dcc670aa63a298b3b032a6b8eafca0cd750cef36d47d26
remote e5dd025706a01f7608081c62121d67c28abcea65c079711a216600c55cc4df4c
hash   1eb97ba65a3508d312f67436ecc61e7971f1d290bc97bfa6b9e9c73cf2b195afeb9514669b176c212ee75a1837263c0abd5f41f42216749b31393738b664f4d7

Other usage:

icy host port        connect to host:port
icy -l port          listen for a connection
icy -k -l port       listen, keep accepting connections
icy -v ...           print key fingerprints and handshake hash

Pipe anything through it:

# receiver
icy -l 9000 > file.bin

# sender
icy localhost 9000 < file.bin

Observe with tcpdump:

sudo tcpdump -i lo0 -n -s0 -X 'tcp port 9000'

or tshark:

sudo tshark -i lo0 -Y 'tcp.port==9000 and tcp.len>0' -T fields -e tcp.payload

Documentation

Overview

Package icy implements a secure, pipelined transport using the Noise Protocol and XChaCha20-Poly1305.

Index

Constants

View Source
const MaxFrameSize = 0xFFFFFF // 16MB

Variables

View Source
var (
	ErrFrameTooLarge       = errors.New("icy: frame too large")
	ErrDecrypt             = errors.New("icy: decrypt failed")
	ErrHandshakeIncomplete = errors.New("icy: handshake incomplete")
	ErrInvalidHeader       = errors.New("icy: invalid header")
	ErrSessionIDMismatch   = errors.New("icy: session ID mismatch")
)

Functions

This section is empty.

Types

type Config

type Config struct {
	Pattern         *noise.HandshakePattern
	KeyPair         *noise.KeyPair
	RemotePublicKey []byte
}

Config holds configuration for the Noise handshake.

type Conn

type Conn struct {
	Reader
	Writer
	textproto.Pipeline
	// contains filtered or unexported fields
}

Conn represents a secure, bidirectional transport for encrypted communication. It implements io.ReadWriteCloser and embeds textproto.Pipeline for concurrent request/response pipelining over a Noise-authenticated channel.

func NewConn

func NewConn(initiator bool, rwc io.ReadWriteCloser, cfg *Config) (*Conn, error)

NewConn performs a Noise handshake over rwc and returns a new encrypted Conn using rwc for I/O.

func (*Conn) Close

func (c *Conn) Close() error

Close closes the connection.

func (*Conn) HandshakeHash

func (c *Conn) HandshakeHash() []byte

HandshakeHash returns the handshake hash.

func (*Conn) PublicKey

func (c *Conn) PublicKey() []byte

PublicKey returns the local static public key.

func (*Conn) RemotePublicKey

func (c *Conn) RemotePublicKey() []byte

RemotePublicKey returns the remote static public key.

func (*Conn) Send

func (c *Conn) Send(p []byte) (id uint, err error)

Send writes data after waiting its turn in the pipeline. It returns the id of the request, for use with StartResponse and EndResponse.

type Reader

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

A Reader reads length-prefixed frames from an underlying reader and decrypts them.

func NewReader

func NewReader(rd io.Reader, dec cipher.AEAD, nonce [24]byte) *Reader

NewReader returns a new Reader reading from rd.

func (*Reader) Read

func (r *Reader) Read(p []byte) (int, error)

Read reads and decrypts the next frame from the underlying reader.

type Session

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

Session holds the state of an established Noise session.

func Negotiate

func Negotiate(initiator bool, rw io.ReadWriter, cfg *Config) (*Session, error)

Negotiate performs a Noise handshake and returns a Session.

func (*Session) Dec

func (s *Session) Dec() cipher.AEAD

Dec returns the AEAD cipher for decrypting incoming messages.

func (*Session) DecNonce

func (s *Session) DecNonce() [24]byte

DecNonce returns the current nonce for decryption.

func (*Session) Enc

func (s *Session) Enc() cipher.AEAD

Enc returns the AEAD cipher for encrypting outgoing messages.

func (*Session) EncNonce

func (s *Session) EncNonce() [24]byte

EncNonce returns the current nonce for encryption.

func (*Session) HandshakeHash

func (s *Session) HandshakeHash() []byte

HandshakeHash returns the handshake hash, useful for channel binding.

func (*Session) PublicKey

func (s *Session) PublicKey() []byte

PublicKey returns the local static public key.

func (*Session) RemotePublicKey

func (s *Session) RemotePublicKey() []byte

RemotePublicKey returns the remote static public key.

type Writer

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

A Writer encrypts data and writes it as length-prefixed frames to an underlying writer.

func NewWriter

func NewWriter(wd *bufio.Writer, enc cipher.AEAD, nonce [24]byte) *Writer

NewWriter returns a new Writer writing to wd.

func (*Writer) Write

func (w *Writer) Write(p []byte) (int, error)

Write encrypts p and writes it as a length-prefixed frame.

Directories

Path Synopsis
cmd
icy command

Jump to

Keyboard shortcuts

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