Documentation
¶
Overview ¶
Package brontide implements Handshake's Brontide P2P transport primitives.
Index ¶
- Constants
- Variables
- func ECDH(pub *btcec.PublicKey, priv *btcec.PrivateKey) ([keySize]byte, error)
- func ECDHBytes(pub []byte, priv *btcec.PrivateKey) ([keySize]byte, error)
- func GenerateKey() (*btcec.PrivateKey, error)
- func IdentityKeyPath(dataDir string) string
- func IdentityStaticKey(priv *btcec.PrivateKey) ([]byte, error)
- func LoadIdentityKey(path string) (*btcec.PrivateKey, error)
- func LoadOrCreateIdentityKey(path string) (*btcec.PrivateKey, bool, error)
- func ParsePublicKey(serialized []byte) (*btcec.PublicKey, error)
- func PublicKeyBytes(priv *btcec.PrivateKey) []byte
- func PublicKeyFromHash(uniform []byte) (*btcec.PublicKey, error)
- func PublicKeyToHash(pub *btcec.PublicKey, rng io.Reader) ([]byte, error)
- func ReadFrame(recv *CipherState, frame []byte) ([]byte, error)
- func SaveIdentityKey(path string, priv *btcec.PrivateKey) error
- func WriteFrame(send *CipherState, payload []byte) ([]byte, error)
- type CipherState
- type Conn
- func ClientHandshake(conn net.Conn, localPriv *btcec.PrivateKey, remotePub []byte) (*Conn, error)
- func ClientHandshakeTimeout(conn net.Conn, localPriv *btcec.PrivateKey, remotePub []byte, ...) (*Conn, error)
- func NewConn(conn net.Conn, send, recv *CipherState) (*Conn, error)
- func ServerHandshake(conn net.Conn, localPriv *btcec.PrivateKey) (*Conn, *btcec.PublicKey, error)
- func ServerHandshakeTimeout(conn net.Conn, localPriv *btcec.PrivateKey, timeout time.Duration) (*Conn, *btcec.PublicKey, error)
- func (c *Conn) Close() error
- func (c *Conn) LocalAddr() net.Addr
- func (c *Conn) Read(p []byte) (int, error)
- func (c *Conn) RemoteAddr() net.Addr
- func (c *Conn) SetDeadline(t time.Time) error
- func (c *Conn) SetReadDeadline(t time.Time) error
- func (c *Conn) SetWriteDeadline(t time.Time) error
- func (c *Conn) Write(p []byte) (int, error)
- type HandshakeState
- func (hs *HandshakeState) GenActOne() ([ActOneSize]byte, error)
- func (hs *HandshakeState) GenActThree() ([ActThreeSize]byte, error)
- func (hs *HandshakeState) GenActTwo() ([ActTwoSize]byte, error)
- func (hs *HandshakeState) RecvActOne(actOne []byte) error
- func (hs *HandshakeState) RecvActThree(actThree []byte) error
- func (hs *HandshakeState) RecvActTwo(actTwo []byte) error
- func (hs *HandshakeState) RemoteStatic() *btcec.PublicKey
- type SymmetricState
- func (s *SymmetricState) ChainKey() [keySize]byte
- func (s *SymmetricState) DecryptHash(ciphertext, tag []byte) ([]byte, error)
- func (s *SymmetricState) Digest() [keySize]byte
- func (s *SymmetricState) EncryptHash(plaintext []byte) ([]byte, []byte, error)
- func (s *SymmetricState) InitSymmetric(protocolName string)
- func (s *SymmetricState) MixHash(parts ...[]byte)
- func (s *SymmetricState) MixKey(input []byte)
- func (s *SymmetricState) Split(initiator bool) (*CipherState, *CipherState, error)
Constants ¶
const ( // ProtocolName is hsd's Noise protocol name for Handshake Brontide. ProtocolName = "Noise_XK_secp256k1_ChaChaPoly_SHA256+SVDW_Squared" // Prologue is mixed into the Handshake Brontide handshake hash. Prologue = "hns" // RotationInterval is hsd's cipher key rotation interval. The cipher // rotates after this many successful encryptions or decryptions. RotationInterval = 1000 )
const ( // HeaderSize is the size of an encrypted hsd Brontide frame header: // 4-byte little-endian payload length plus a 16-byte authentication tag. HeaderSize = 4 + tagSize // MaxMessageSize is hsd's MAX_MESSAGE plus the 9-byte Handshake packet // envelope that is encrypted inside Brontide frames. MaxMessageSize = 8*1000*1000 + 9 )
const ( // ActOneSize is hsd's ACT_ONE_SIZE: a 64-byte uniform ephemeral key // encoding plus a 16-byte authentication tag. ActOneSize = UniformPublicKeySize + tagSize // ActTwoSize is hsd's ACT_TWO_SIZE: a 64-byte uniform ephemeral key // encoding plus a 16-byte authentication tag. ActTwoSize = UniformPublicKeySize + tagSize // ActThreeSize is hsd's ACT_THREE_SIZE: a 33-byte encrypted static key // plus two 16-byte authentication tags. ActThreeSize = PublicKeySize + tagSize + tagSize // HandshakeTimeout bounds a complete act exchange, matching hsd's // Peer.CONNECT_TIMEOUT, which covers the Brontide handshake before the // stream emits its connect event. HandshakeTimeout = 5 * time.Second )
hsd's Noise_XK three-act message pattern:
Act One (initiator -> responder): e, es Act Two (responder -> initiator): e, ee Act Three (initiator -> responder): s, se
Unlike LND's Brontide, hsd's acts carry no version byte: the ephemeral keys in acts one and two are sent as 64-byte Elligator Squared encodings, keeping the entire handshake indistinguishable from random bytes.
const ( // PrivateKeySize is the size of a serialized secp256k1 private key. PrivateKeySize = btcec.PrivKeyBytesLen // PublicKeySize is the size of a compressed secp256k1 public key. PublicKeySize = btcec.PubKeyBytesLenCompressed )
const (
// IdentityKeyFile is the default file name for a Brontide node identity key.
IdentityKeyFile = "brontide.key"
)
const ( // UniformPublicKeySize is the size of an Elligator Squared encoded // secp256k1 point: two big-endian field elements. UniformPublicKeySize = 64 )
Variables ¶
var ( // ErrInvalidCipher is returned when a Brontide cipher state is nil. ErrInvalidCipher = errors.New("brontide: invalid cipher") // ErrInvalidKeySize is returned when a cipher key or salt is not 32 bytes. ErrInvalidKeySize = errors.New("brontide: invalid key size") // ErrDecrypt is returned when ChaCha20-Poly1305 authentication fails. ErrDecrypt = errors.New("brontide: decrypt failed") )
var ( // ErrInvalidPoint is returned when a secp256k1 point cannot be encoded // to, or decoded from, its Elligator Squared representation. It matches // bcrypto's 'Invalid point.' error. ErrInvalidPoint = errors.New("brontide: invalid point") // ErrInvalidUniformSize is returned when an Elligator Squared encoding // is not exactly 64 bytes. It matches bcrypto's 'Invalid hash size.'. ErrInvalidUniformSize = errors.New("brontide: invalid uniform key size") )
var ( // ErrFrameTooLarge is returned when a Brontide frame payload exceeds // hsd's maximum encrypted message size. ErrFrameTooLarge = errors.New("brontide: frame too large") // ErrShortFrame is returned when a complete-frame helper receives too // few bytes to contain a valid Brontide frame. ErrShortFrame = errors.New("brontide: short frame") // ErrFrameSizeMismatch is returned when the authenticated frame length // does not match the bytes supplied to a complete-frame helper. ErrFrameSizeMismatch = errors.New("brontide: frame size mismatch") )
var ( // ErrActSize is returned when a handshake act has the wrong length, // matching hsd's 'Act N: bad size.' errors. ErrActSize = errors.New("brontide: bad act size") // ErrActTag is returned when a handshake act fails authentication, // matching hsd's 'Act N: bad tag.' errors. ErrActTag = errors.New("brontide: bad act tag") // ErrHandshakeState is returned when handshake state is missing for the // requested act, such as an initiator without a remote static key. ErrHandshakeState = errors.New("brontide: invalid handshake state") )
var ( // ErrInvalidIdentityPath is returned when an identity-key path is empty. ErrInvalidIdentityPath = errors.New("brontide: invalid identity path") // ErrInvalidIdentityKey is returned when stored identity-key bytes are // malformed or outside the secp256k1 private key range. ErrInvalidIdentityKey = errors.New("brontide: invalid identity key") // ErrInsecureIdentityKeyPermissions is returned when a stored identity // key is readable or writable by group or other users. ErrInsecureIdentityKeyPermissions = errors.New( "brontide: insecure identity key permissions", ) )
var ( // ErrInvalidConn is returned when a Brontide connection wrapper receives // a nil connection. ErrInvalidConn = errors.New("brontide: invalid connection") )
var ( // ErrInvalidKey is returned when Brontide key material is nil or invalid. ErrInvalidKey = errors.New("brontide: invalid key") )
Functions ¶
func ECDHBytes ¶
func ECDHBytes(pub []byte, priv *btcec.PrivateKey) ([keySize]byte, error)
ECDHBytes parses pub and returns hsd's Brontide ECDH secret: SHA256(compressed shared point).
func GenerateKey ¶
func GenerateKey() (*btcec.PrivateKey, error)
GenerateKey creates a secp256k1 private key suitable for Brontide static or ephemeral key material.
func IdentityKeyPath ¶
IdentityKeyPath returns the default Brontide identity-key path under dataDir.
func IdentityStaticKey ¶
func IdentityStaticKey(priv *btcec.PrivateKey) ([]byte, error)
IdentityStaticKey returns the compressed secp256k1 public key advertised as the node's Brontide static identity key.
func LoadIdentityKey ¶
func LoadIdentityKey(path string) (*btcec.PrivateKey, error)
LoadIdentityKey loads a serialized secp256k1 Brontide identity key from path.
func LoadOrCreateIdentityKey ¶
func LoadOrCreateIdentityKey(path string) (*btcec.PrivateKey, bool, error)
LoadOrCreateIdentityKey loads the node Brontide identity key at path, or generates and persists a new key when none exists. The returned bool is true when a new key was created.
func ParsePublicKey ¶
ParsePublicKey parses a compressed secp256k1 public key.
func PublicKeyBytes ¶
func PublicKeyBytes(priv *btcec.PrivateKey) []byte
PublicKeyBytes returns the compressed public key for priv.
func PublicKeyFromHash ¶
PublicKeyFromHash decodes a 64-byte Elligator Squared encoding into a secp256k1 public key, matching bcrypto's publicKeyFromHash. Every 64-byte string decodes to a valid curve point except the negligible case where the two mapped points sum to infinity.
func PublicKeyToHash ¶
PublicKeyToHash encodes a secp256k1 public key as 64 bytes that are indistinguishable from uniformly random bytes, matching bcrypto's publicKeyToHash. The encoding is randomized: rng supplies the random field elements and preimage hints, and defaults to crypto/rand when nil. The returned bytes decode back to pub via PublicKeyFromHash.
func ReadFrame ¶
func ReadFrame(recv *CipherState, frame []byte) ([]byte, error)
ReadFrame decrypts a complete hsd Brontide stream frame and returns its payload. A frame consumes two cipher nonces when both the header and payload authenticate successfully.
func SaveIdentityKey ¶
func SaveIdentityKey(path string, priv *btcec.PrivateKey) error
SaveIdentityKey writes a Brontide identity key to path using owner-only file permissions. Existing files are replaced.
func WriteFrame ¶
func WriteFrame(send *CipherState, payload []byte) ([]byte, error)
WriteFrame encrypts payload into one hsd Brontide stream frame. A frame consumes two cipher nonces: one for the length header and one for the body.
Types ¶
type CipherState ¶
type CipherState struct {
// contains filtered or unexported fields
}
CipherState is hsd's Brontide ChaCha20-Poly1305 cipher state. It keeps a key, a salt used for key rotation, and a monotonically increasing nonce.
func NewCipherState ¶
func NewCipherState() *CipherState
NewCipherState returns a cipher initialized with the all-zero key and salt, matching hsd's initial Brontide cipher state.
func (*CipherState) Decrypt ¶
func (c *CipherState) Decrypt(ciphertext, tag, ad []byte) ([]byte, error)
Decrypt authenticates and decrypts ciphertext with a detached tag and optional associated data.
func (*CipherState) Encrypt ¶
func (c *CipherState) Encrypt(plaintext, ad []byte) ([]byte, []byte, error)
Encrypt encrypts plaintext with optional associated data. It returns the ciphertext and detached authentication tag.
func (*CipherState) InitKey ¶
func (c *CipherState) InitKey(key []byte) error
InitKey replaces the cipher key and resets the nonce.
func (*CipherState) InitSalt ¶
func (c *CipherState) InitSalt(key, salt []byte) error
InitSalt replaces the cipher salt, then initializes the key.
func (*CipherState) Nonce ¶
func (c *CipherState) Nonce() uint32
Nonce returns the current message nonce. It is exposed for tests and for future transport diagnostics.
type Conn ¶
type Conn struct {
// contains filtered or unexported fields
}
Conn wraps a net.Conn with hsd-compatible Brontide frame encryption. It expects the Noise handshake to have already derived send and receive ciphers.
func ClientHandshake ¶
ClientHandshake runs the initiator side of the Brontide handshake over conn and returns the encrypted connection. remotePub is the responder's compressed static public key. The exchange is bounded by HandshakeTimeout.
func ClientHandshakeTimeout ¶
func ClientHandshakeTimeout(conn net.Conn, localPriv *btcec.PrivateKey, remotePub []byte, timeout time.Duration) (*Conn, error)
ClientHandshakeTimeout is ClientHandshake with a caller-selected timeout covering the complete act exchange.
func NewConn ¶
func NewConn(conn net.Conn, send, recv *CipherState) (*Conn, error)
NewConn returns a Brontide-encrypted connection using established ciphers.
func ServerHandshake ¶
ServerHandshake runs the responder side of the Brontide handshake over conn and returns the encrypted connection along with the initiator's authenticated static public key. The exchange is bounded by HandshakeTimeout.
func ServerHandshakeTimeout ¶
func ServerHandshakeTimeout(conn net.Conn, localPriv *btcec.PrivateKey, timeout time.Duration) (*Conn, *btcec.PublicKey, error)
ServerHandshakeTimeout is ServerHandshake with a caller-selected timeout covering the complete act exchange.
func (*Conn) Read ¶
Read decrypts bytes from the Brontide stream. Frame boundaries are hidden from callers; unread bytes from a decrypted frame are buffered.
func (*Conn) RemoteAddr ¶
RemoteAddr returns the remote network address.
func (*Conn) SetDeadline ¶
SetDeadline sets both read and write deadlines on the underlying connection.
func (*Conn) SetReadDeadline ¶
SetReadDeadline sets the read deadline on the underlying connection.
func (*Conn) SetWriteDeadline ¶
SetWriteDeadline sets the write deadline on the underlying connection.
type HandshakeState ¶
type HandshakeState struct {
SymmetricState
// contains filtered or unexported fields
}
HandshakeState is hsd's Brontide handshake state: a Noise symmetric state plus the key material accumulated across the three Noise_XK acts.
func NewHandshakeState ¶
func NewHandshakeState(initiator bool, localPriv *btcec.PrivateKey, remotePub *btcec.PublicKey) (*HandshakeState, error)
NewHandshakeState initializes Brontide handshake state for one side of a connection, mirroring hsd's HandshakeState.initState. Initiators must supply the responder's static public key; responders pass nil.
func (*HandshakeState) GenActOne ¶
func (hs *HandshakeState) GenActOne() ([ActOneSize]byte, error)
GenActOne generates act one for the initiator: a uniform-encoded ephemeral key and a tag binding the es ECDH result.
func (*HandshakeState) GenActThree ¶
func (hs *HandshakeState) GenActThree() ([ActThreeSize]byte, error)
GenActThree generates act three for the initiator: the encrypted local static key and a tag binding the se ECDH result. It derives the final transport ciphers.
func (*HandshakeState) GenActTwo ¶
func (hs *HandshakeState) GenActTwo() ([ActTwoSize]byte, error)
GenActTwo generates act two for the responder: a uniform-encoded ephemeral key and a tag binding the ee ECDH result.
func (*HandshakeState) RecvActOne ¶
func (hs *HandshakeState) RecvActOne(actOne []byte) error
RecvActOne processes act one on the responder.
func (*HandshakeState) RecvActThree ¶
func (hs *HandshakeState) RecvActThree(actThree []byte) error
RecvActThree processes act three on the responder, authenticating the initiator's static key and deriving the final transport ciphers.
func (*HandshakeState) RecvActTwo ¶
func (hs *HandshakeState) RecvActTwo(actTwo []byte) error
RecvActTwo processes act two on the initiator.
func (*HandshakeState) RemoteStatic ¶
func (hs *HandshakeState) RemoteStatic() *btcec.PublicKey
RemoteStatic returns the remote static public key: the key supplied at initialization for initiators, or the key learned in act three for responders.
type SymmetricState ¶
type SymmetricState struct {
// contains filtered or unexported fields
}
SymmetricState is the Noise symmetric state used by Handshake Brontide.
func NewSymmetricState ¶
func NewSymmetricState() *SymmetricState
NewSymmetricState initializes a symmetric state with hsd's protocol name.
func (*SymmetricState) ChainKey ¶
func (s *SymmetricState) ChainKey() [keySize]byte
ChainKey returns the current chaining key.
func (*SymmetricState) DecryptHash ¶
func (s *SymmetricState) DecryptHash(ciphertext, tag []byte) ([]byte, error)
DecryptHash authenticates and decrypts ciphertext with the current digest as associated data, then mixes the ciphertext and tag into the digest.
func (*SymmetricState) Digest ¶
func (s *SymmetricState) Digest() [keySize]byte
Digest returns the current handshake digest.
func (*SymmetricState) EncryptHash ¶
func (s *SymmetricState) EncryptHash(plaintext []byte) ([]byte, []byte, error)
EncryptHash encrypts plaintext with the current digest as associated data and mixes the resulting ciphertext and tag into the digest.
func (*SymmetricState) InitSymmetric ¶
func (s *SymmetricState) InitSymmetric(protocolName string)
InitSymmetric initializes the handshake digest, chaining key, and zero-key cipher state for a Noise protocol name.
func (*SymmetricState) MixHash ¶
func (s *SymmetricState) MixHash(parts ...[]byte)
MixHash updates the handshake digest with one or more byte slices.
func (*SymmetricState) MixKey ¶
func (s *SymmetricState) MixKey(input []byte)
MixKey mixes input key material into the chaining key and reinitializes the handshake cipher with the derived temporary key.
func (*SymmetricState) Split ¶
func (s *SymmetricState) Split(initiator bool) (*CipherState, *CipherState, error)
Split derives send and receive ciphers from the final chaining key. The initiator uses the first derived key for sending; the responder uses it for receiving, matching hsd.