Documentation
¶
Overview ¶
Package spc implements the Secure Channel Protocol, a custom TLS-inspired, check the github for more info.
Index ¶
- Constants
- func ComputePSKProof(psk []byte, data ...[]byte) []byte
- func Decrypt(key []byte, nonce []byte, ciphertext []byte) ([]byte, error)
- func DeriveSessionKey(sharedSecret [32]byte, psk []byte, clientNonce []byte, serverNonce []byte) ([]byte, error)
- func EncodeClientHello(p ClientHelloPayload) []byte
- func EncodeDataPayload(p DataPayload) []byte
- func EncodeError(p ErrorPayload) []byte
- func EncodeServerHello(p ServerHelloPayload) []byte
- func Encrypt(key []byte, nonce []byte, plaintext []byte) ([]byte, error)
- func GenerateKeypair() (publicKey [32]byte, privateKey [32]byte, err error)
- func RandomNonce(size int) ([]byte, error)
- func SharedSecret(privateKey [32]byte, peerPublicKey [32]byte) ([32]byte, error)
- func WritePacket(w io.Writer, p Packet) error
- type ClientHelloPayload
- type Config
- type DataPayload
- type ErrorPayload
- type Listener
- type MessageType
- type NonceCounter
- type Packet
- type ServerHelloPayload
- type Session
Constants ¶
const ( ErrUnknown byte = 0x00 // unspecified error ErrInvalidPSK byte = 0x01 // PSK proof verification failed ErrHandshakeFail byte = 0x02 // Done MAC verification failed ErrInvalidMessage byte = 0x03 // unexpected message type received )
SCP error codes sent in MsgError packets
const ( NonceSize = 16 // random per handsake PublicKeySize = 32 // X25519 public key PSKProofSize = 32 // HMAC-SHA256 output )
Variables ¶
This section is empty.
Functions ¶
func ComputePSKProof ¶
ComputePSKProof computes an HMAC-SHA256 over the data fields, keyed by the PSK used to prove PSK knowledge during the handshake without revealing the PSK itself
func Decrypt ¶
Decrypt decrypts ciphertext using ChaCha20-Poly1305 with the given key and nonce Returns an error if authentication fails, any tampering with ciphertext will cause the decryption to fail entirely
func DeriveSessionKey ¶
func DeriveSessionKey(sharedSecret [32]byte, psk []byte, clientNonce []byte, serverNonce []byte) ([]byte, error)
DeriveSessionKey derives a 32-byte session key from ECDH shared secret using HKDF-SHA256 The PSK is used as HKDF salt and both nonces are included into the info field to bind the key to this specific session
func EncodeClientHello ¶
func EncodeClientHello(p ClientHelloPayload) []byte
func EncodeDataPayload ¶
func EncodeDataPayload(p DataPayload) []byte
func EncodeError ¶
func EncodeError(p ErrorPayload) []byte
func EncodeServerHello ¶
func EncodeServerHello(p ServerHelloPayload) []byte
func Encrypt ¶
Encrypt encrypts plaintext using ChaCha20-Poly1305 with the given key and nonce The nonce must be 12 bytes as thats what ChaCha20 uses Returns ciphertext with a 16-byte Poly1305 auth tag appended
func GenerateKeypair ¶
GenerateKeypair generates a fresh pair of ephemeral X25519 keypair a new keypair should be generated for EVERY handshake
func RandomNonce ¶
func SharedSecret ¶
SharedSecret computes the X25519 Diffie-Hellman shared secret from a local private key and a peer's public key both sides independently arrive at the same shared secret
Types ¶
type ClientHelloPayload ¶
type ClientHelloPayload struct {
Nonce [NonceSize]byte
PublicKey [PublicKeySize]byte
PSKProof [PSKProofSize]byte
}
func DecodeClientHello ¶
func DecodeClientHello(payload []byte) (ClientHelloPayload, error)
type Config ¶
type Config struct {
// PSK is the pre-shared key used for mutual authentication.
// Both sides must use the same PSK.
PSK []byte
}
Config holds the configuration for an SCP connection, well duh.
type DataPayload ¶
Data ============
func DecodeDataPayload ¶
func DecodeDataPayload(payload []byte) (DataPayload, error)
type ErrorPayload ¶
func DecodeError ¶
func DecodeError(payload []byte) (ErrorPayload, error)
type Listener ¶
type Listener struct {
// contains filtered or unexported fields
}
Listener accepts incoming SCP connections on a TCP address
func Listen ¶
Listen creates a Listener on the given TCP address Each accepted connection will perform the SCP server handshake using the PSK in cfg before a Session is returned
type MessageType ¶
type MessageType byte
MessageType identifies the type of an SCP packet
const ( MsgClientHello MessageType = 0x01 // opens the handshake MsgServerHello MessageType = 0x02 // server response to ClientHello MsgDone MessageType = 0x03 // handshake verification MsgData MessageType = 0x04 // encrypted application data MsgError MessageType = 0x05 // protocol error, terminates connection )
SCP message types
type NonceCounter ¶
type NonceCounter struct {
// contains filtered or unexported fields
}
NonceCounter generates monotonically increasing 12-byte nonces for use with ChaCha20-Poly1305 The counter is encoded as a big-endian uint64 in the last 8 bytes of the nonce NOT safe for concurrent use
func NewNonceCounter ¶
func NewNonceCounter() *NonceCounter
NewNonceCounter returns a new NounceCounter starting at zero
func (*NonceCounter) Next ¶
func (n *NonceCounter) Next() []byte
Next returns the next 12-byte nonce and increments the counter must not be called more than 2^64 times with the same key, but tbh no one is gonna try that lmao
type Packet ¶
type Packet struct {
Type MessageType
Payload []byte
}
Packet is the basic unit of the SCP wire format Every SCP message is framed as a 5-byte header (type + length) followed by a payload of exactly length bytes
type ServerHelloPayload ¶
type ServerHelloPayload struct {
Nonce [NonceSize]byte
PublicKey [PublicKeySize]byte
PSKProof [PSKProofSize]byte
}
func DecodeServerHello ¶
func DecodeServerHello(payload []byte) (ServerHelloPayload, error)
type Session ¶
type Session struct {
Conn net.Conn
SessionKey []byte
NonceCounter NonceCounter
}
Session represents an established SCP connection Use Send and Receive to exchange encrypted messages
func Dial ¶
Dial connects to an SCP server at addr and performs the handshake Returns an established Session ready for sending and receiving data Handshake verifies mutual PSK knowledge before returning