noise

package
v0.3.13 Latest Latest
Warning

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

Go to latest
Published: Feb 22, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

README

README

This package provides a Go implementation of the Noise Protocol (revision 34), closely adhering to the specifications.

All documented Handshake Patterns are pre-registered in the package pattern registry . You can also define new patterns using the same syntax as in the specifications. The package supports the psk and fallback modifiers as specified.

All cryptographic algorithms from the specifications are pre-registered, except, X448 which is omitted due to lack of support in Go's standard crypto libraries. Additional algorithms can be registered as needed.

Documentation

Index

Constants

View Source
const (
	MAX_UINT64       = 0xFFFF_FFFF_FFFF_FFFF
	CIPHER_MAX_NONCE = MAX_UINT64 - 1
)
View Source
const (
	CIPHER_AES256_GCM        = "AESGCM"
	CIPHER_CHACHA20_POLY1305 = "ChaChaPoly"
)
View Source
const (
	HASH_SHA256  = "SHA256"
	HASH_SHA512  = "SHA512"
	HASH_BLAKE2B = "BLAKE2b"
	HASH_BLAKE2S = "BLAKE2s"
)
View Source
const (
	// All package errors are wrapping Error
	Error = errorFlag("noise: error")
)

Variables

This section is empty.

Functions

func LoadPattern

func LoadPattern(name string, dst *HandshakePattern) error

LoadPattern copies the pattern referenced by name in dst. It errors if name does not correspond to a registered pattern.

func MustRegisterAEAD

func MustRegisterAEAD(name string, factory AEADFactory)

MustRegisterAEAD adds factory to the AEAD registry. It panics if name is already in use or factory is invalid.

func MustRegisterHash

func MustRegisterHash(name string, hash crypto.Hash)

MustRegisterHash adds hash to the Hash registry. It panics if name is already in use or hash is invalid.

func MustRegisterPatternSpec

func MustRegisterPatternSpec(dsl string)

MustRegisterPatternSpec parses dsl which contains name of the pattern and definition of the pattern in noise specification language and stores the resulting HandshakePattern in the pattern registry. It panics if provided dsl is invalid or if the parsed pattern name is already in use.

Refers to noise protocol specs section 7 for a description of the syntax of the language used to specify handshakes.

func ParseProtocol

func ParseProtocol(protoname string, proto *NoiseProto) error

ParseProtocol extracts the noise protocol name components and stores them into proto.

Valid protoname looks like "Noise_XX_25519_AESGCM_SHA256". Refers to noise protocol specs section 8, for details on how valid names are formed.

func RegisterAEAD

func RegisterAEAD(name string, factory AEADFactory) error

RegisterAEAD adds factory to the AEAD registry. It errors if name is already in use or factory is invalid.

func RegisterHash

func RegisterHash(name string, hash crypto.Hash) error

RegisterHash adds hash to the Hash registry. It errors if name is already in use or hash is invalid.

func RegisterPattern

func RegisterPattern(name string, pattern *HandshakePattern) error

RegisterPattern store the pattern in the pattern registry. It errors if name is already in use or if the pattern is invalid.

Types

type AEAD

type AEAD interface {
	cipher.AEAD

	// Rekey changes AEAD key to newkey. It errors if newkey is not compatible with AEAD algorithm.
	Rekey(newkey []byte, nonce []byte) error

	// FillNonce transfers nonce value n to nonce slice.
	FillNonce(nonce []byte, n uint64)
}

AEAD extends cipher.AEAD with methods usefull for noise protocol implementation.

type AEADFactory

type AEADFactory interface {

	// New returns an AEAD instance. It errors if key is not compatible with AEAD algorithm.
	New(key []byte) (AEAD, error)
}

AEADFactory allows obtaining an AEAD instance.

func GetAEADFactory

func GetAEADFactory(name string) (AEADFactory, error)

GetAEADFactory loads an AEADFactory from the registry. It errors if no factory was registered with name.

type AEADFactoryFunc

type AEADFactoryFunc func([]byte) (AEAD, error)

AEADFactoryFunc is an adapter to allow the use of ordinary functions as AEADFactory.

func (AEADFactoryFunc) New

func (self AEADFactoryFunc) New(key []byte) (AEAD, error)

New returns an AEAD instance. It errors if key is not compatible with AEAD algorithm.

type AcceptOrRejectAnyKey

type AcceptOrRejectAnyKey struct {

	// desired verification status. If nil all verified static keys are valid...
	Status error
	// contains filtered or unexported fields
}

AcceptOrRejectAnyKey is a CredentialVerifier that allows accepting or rejecting any static key.

AcceptAnyOrRejectAnyKey is provided to help testing noise protocol implementations.

func NewAcceptOrRejectAnyKey

func NewAcceptOrRejectAnyKey() *AcceptOrRejectAnyKey

NewAcceptOrRejectAnyKey returns a CredentialVerifier that always fails. Change the Status field to nil for Verify to always succeed.

func (*AcceptOrRejectAnyKey) ReadSize

func (self *AcceptOrRejectAnyKey) ReadSize(hs *HandshakeState) int

ReadSize returns the byte size of inner configuration DH PublicKey.

func (*AcceptOrRejectAnyKey) Reset

func (self *AcceptOrRejectAnyKey) Reset()

Reset clears internal state to allow reuse with another handshake.

func (*AcceptOrRejectAnyKey) Verify

func (self *AcceptOrRejectAnyKey) Verify(_ *HandshakeState, data []byte) (int, error)

Verify errors if inner Status is not nil.

type CipherState

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

CipherState holds AEAD cipher usage state, ie nonce and key.

CipherState appears in section 5.1 of the noise protocol specs.

func (*CipherState) DecryptWithAd

func (self *CipherState) DecryptWithAd(ad, ciphertext []byte) ([]byte, error)

DecryptWithAd performs authenticated decryption of ciphertext if the CipherState has a key otherwise it returns ciphertext inchanged.

The ad parameter maybe nil, it shall match the ad used for obtaining ciphertext. ad corresponds to AEAD "additional data" and it was used alongside plaintext and key to calculate the ciphertext authentication tag. DecryptWithAd appears in section 5.1 of the noise protocol specs.

func (*CipherState) EncryptWithAd

func (self *CipherState) EncryptWithAd(ad, plaintext []byte) ([]byte, error)

EncryptWithAd performs authenticated encryption of plaintext if the CipherState has a key otherwise it returns plaintext inchanged.

The ad parameter maybe nil, it corresponds to AEAD "additional data" and it is used alongside plaintext and key to calculate the ciphertext authentication tag. EncryptWithAd appears in section 5.1 of the noise protocol specs.

func (*CipherState) HasKey

func (self *CipherState) HasKey() bool

HasKey returns true if the CipherState contains an initialized aead.

Haskey appears in section 5.1 of the noise protocol specs.

func (*CipherState) Init

func (self *CipherState) Init(cipherFactory AEADFactory) error

Init set inner AEAD factory and zero the key.

Init appears in section 5.1 of the noise protocol specs.

func (*CipherState) InitializeKey

func (self *CipherState) InitializeKey(newkey []byte) error

InitializeKey creates internal aead using newkey. A nil newkey will zero the internal key and aead. InitializeKey errors if newkey is not correctly sized.

InitializeKey appears in section 5.1 of the noise protocol specs.

func (*CipherState) Rekey

func (self *CipherState) Rekey() error

Rekey changes the CipherState internal key. It errors if the CipherState does not have a key.

Rekey appears in section 5.1 of the noise protocol specs.

func (*CipherState) SetNonce

func (self *CipherState) SetNonce(n uint64)

SetNonce set internal nonce value to n.

SetNonce is usefull when the CipherState is used after completion of the noise protocol handshake. If transport messages are produced concurrently or maybe received out of order then application will transfert nonce value with transport message. Receiver shall verify that received nonce was not previously used and use SetNonce prior to attend decryption... SetNonce appears in section 5.1 of the noise protocol specs.

type Config

type Config struct {
	// "name" of the noise protocol, eg "Noise_XX_25519_AESGCM_SHA256".
	// Refers to noise protocol specs section 8, for details on how valid names are formed.
	ProtoName string

	// object that defines how to process the handshake messages.
	HandshakePattern HandshakePattern

	// handshake cipher factory.
	CipherFactory AEADFactory

	// handshake Hash algorithm.
	HashAlgo Hash

	// handshake ECDH curve
	CurveAlgo algos.Curve
}

Config holds noise protocol handshake configuration

func (*Config) Load

func (self *Config) Load(protoname string) error

Load parse protoname and loads the algorithms it references into the Config.

Valid protoname looks like "Noise_XX_25519_AESGCM_SHA256". Refers to noise protocol specs section 8, for details on how valid names are formed.

type CredentialVerifier

type CredentialVerifier interface {

	// ReadSize returns the expected size of the next data to be passed to Verify.
	ReadSize(hs *HandshakeState) int

	// Verify uses data to perform some validation. If the validation fails it returns
	// a non nil error, otherwise it returns a nil error and an integer in [0..len(data)] range
	// that indicates the number of bytes to be removed from the data buffer prior to continue
	// processing the handshake.
	//
	// data to be verified are plaintext extracted from received handshake messages. For example data maybe
	// a user identifier, a public key or a public key certificate...
	//
	// Verify may update the provided HandshakeState. This can be leveraged for example to add psks to an
	// HandshakeState after having verified an userId...
	//
	// Verify shall not retain hs or data.
	Verify(hs *HandshakeState, data []byte) (int, error)

	// Reset clears internal state to allow reuse with another handshake.
	Reset()
}

CredentialVerifier is used to track verification state of a certain credential transmitted in an handshake message.

type HandshakeParams

type HandshakeParams struct {
	Cfg                Config
	Initiator          bool
	Prologue           []byte
	StaticKeypair      *Keypair
	EphemeralKeypair   *Keypair
	RemoteStaticKey    *PublicKey
	RemoteEphemeralKey *PublicKey
	Psks               [][]byte
}

HandshakeParams holds HandshakeState.Initialize parameters.

type HandshakePattern

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

HandshakePattern holds informations that defines a noise protocol handshake.

func NewPattern

func NewPattern(dsl string) (*HandshakePattern, error)

NewPattern parses dsl that contains a noise protocol handshake description and constructs the corresponding HandshakePattern. It errors if provided dsl is invalid.

Refers to noise protocol specs section 7 for a description of the syntax of the language used to define handshakes.

You should not normally use NewPattern to create the HandshakePattern{} you need. LoadPattern or Config.Load allows you to obtain or safely modify one of the preverified patterns referenced in the noise protocol specs.

func (HandshakePattern) Dsl

func (self HandshakePattern) Dsl() string

Dsl returns a string that encodes the HandshakePattern using noise protocol specs pattern definition language.

Refers to noise protocol specs section 7 for a description of the syntax of the language used to define handshake patterns.

func (HandshakePattern) OneWay

func (self HandshakePattern) OneWay() bool

OneWay returns true if the HandshakePattern is one way.

Refers to noise protocol specs section 7.4 for a description of the oneway patterns.

type HandshakeState

type HandshakeState struct {
	SymetricState
	// contains filtered or unexported fields
}

HandshakeState holds noise protocol handshake execution state.

HandshakeState appears in section 5.3 of the noise protocol specs.

func (*HandshakeState) DHLen

func (self *HandshakeState) DHLen() int

DHLen returns ECDH PublicKey byte size.

This method is provided to comply with noise specs section 4.1 that mentions the DHLEN constant. noise specs are a bit ambiguous as it states that DHLEN is both the PublicKey size and ECDH shared secret size. This equality holds only for X25519 and X448.

func (*HandshakeState) Initialize

func (self *HandshakeState) Initialize(params HandshakeParams) error

Initialize set handshake initial state. It errors if provided parameters are not compatible with provided cfg.

Initialize appears in section 5.3 of the noise protocol specs.

func (*HandshakeState) ReadMessage

func (self *HandshakeState) ReadMessage(message []byte, payload io.Writer) (bool, error)

ReadMessage processes incoming handshake message taking into account inner state. The returned bool is true when the handshake is completed.

ReadMessage appears in section 5.3 of the noise protocol specs.

func (*HandshakeState) RemoteStaticKey

func (self *HandshakeState) RemoteStaticKey() *PublicKey

RemoteStaticKey returns the remote static PublicKey.

func (*HandshakeState) SetPsks

func (self *HandshakeState) SetPsks(psks ...[]byte) error

func (*HandshakeState) Split

func (self *HandshakeState) Split(dst *TransportCipherPair) error

Split initializes a TransportCipherPair using internal state.

Split should only be called at the end of the handshake.

Split appears in noise protocol specs section 5.2.

func (*HandshakeState) StaticKeypair

func (self *HandshakeState) StaticKeypair() *Keypair

StaticKeypair returns the local static Keypair.

func (*HandshakeState) WriteMessage

func (self *HandshakeState) WriteMessage(payload []byte, message io.Writer) (bool, error)

WriteMessage prepares a new handshake message taking into account inner state and payload parameter. The returned bool is true when the handshake is completed.

WriteMessage appears in section 5.3 of the noise protocol specs.

type Hash

type Hash struct {
	crypto.Hash
}

Hash embeds the crypto.Hash type and adds methods usefull for noise protocol implementation.

func GetHash

func GetHash(name string) (Hash, error)

GetHash loads Hash implementation from the registry. It errors if no hash was registered with name.

func (Hash) Kdf

func (self Hash) Kdf(ck, ikm []byte, keys ...[]byte) error

Kdf executes HKDF with ikm as secret, ck as salt and nil info. It fills each of the provided keys with HKDF generated bytes.

Kdf implementation appears in noise protocol specs, section 4.3.

type Keypair

type Keypair = ecdh.PrivateKey

type NoiseProto

type NoiseProto struct {
	Name                      string
	HandshakePattern          string
	HandshakePatternModifiers []string
	CurveAlgo                 string
	CipherAlgo                string
	HashAlgo                  string
}

NoiseProto holds the components of valid noise protocol names. Refers to noise protocol specs section 8, for details on how valid names are formed.

type PatternModifier

type PatternModifier interface {
	Modify(ptrn HandshakePattern) (HandshakePattern, error)
}

PatternModifier is an interface that allows modifying HandshakePattern.

func GetModifier

func GetModifier(name string) (PatternModifier, error)

GetModifier allows retrieving a PatternModifier by name. It errors if the provided name is invalid.

type PublicKey

type PublicKey = ecdh.PublicKey

type SymetricState

type SymetricState struct {
	CipherState
	// contains filtered or unexported fields
}

SymetricState holds noise protocol handshake symetric state.

SymetricState appears in noise protocol specs section 5.2.

func (*SymetricState) DecryptAndHash

func (self *SymetricState) DecryptAndHash(ciphertext []byte) ([]byte, error)

DecryptAndHash returns plaintext decrypted using inner CipherState. After plaintext is decrypted the received ciphertext is mixed into the SymetricState.

DecryptAndHash uses internal state to authenticate received ciphertext. ciphertext can be decrypted only if internal state is exactly same as sender before ciphertext encryption.

DecryptAndHash appears in noise protocol specs section 5.2.

func (*SymetricState) EncryptAndHash

func (self *SymetricState) EncryptAndHash(plaintext []byte) ([]byte, error)

EncryptAndHash returns ciphertext encrypted using inner CipherState. The ciphertext is mixed into the SymetricState before being returned.

EncryptAndHash uses internal state to authenticate returned ciphertext. ciphertext recipient will be able to decrypt the returned ciphertext only if its state is exactly same as self.

EncryptAndHash appears in noise protocol specs section 5.2.

func (*SymetricState) GetHandshakeHash

func (self *SymetricState) GetHandshakeHash() []byte

GetHandshakeHash returns SymetricState h state.

GetHandshakeHash is normally called at the end of the handshake.

GetHandshakeHash appears in noise protocol specs section 5.2.

func (*SymetricState) Init

func (self *SymetricState) Init(protoname string, cipherfactory AEADFactory, hash Hash) error

Init set SymetricState initial state.

func (*SymetricState) InitializeSymetric

func (self *SymetricState) InitializeSymetric(protoname string) error

InitializeSymetric set SymetricState initial state reading configuration information from protoname.

InitializeSymetric is provided as it appears in noise protocol specs section 5.2. In most cases, it is preferrable to initialize SymetricState using Init as it is more efficient.

func (*SymetricState) MixHash

func (self *SymetricState) MixHash(data []byte)

MixHash mixes data into the SymetricState state.

MixHash appears in noise protocol specs section 5.2.

func (*SymetricState) MixKey

func (self *SymetricState) MixKey(ikm []byte) error

MixKey mixes ikm into the SymetricState state.

MixKey appears in noise protocol specs section 5.2.

func (*SymetricState) MixKeyAndHash

func (self *SymetricState) MixKeyAndHash(ikm []byte) error

MixKeyAndHash mixes ikm into the SymetricState state.

MixKeyAndHash appears in noise protocol specs section 5.2.

type TestMessage

type TestMessage struct {
	Payload    utils.HexBinary `json:"payload"`
	CipherText utils.HexBinary `json:"ciphertext"`
}

TestMessage holds noise protocol test vector message fields.

type TestVector

type TestVector struct {
	ProtocolName                string            `json:"protocol_name"`
	InitiatorPrologue           utils.HexBinary   `json:"init_prologue"`
	InitiatorEphemeralKey       utils.HexBinary   `json:"init_ephemeral"`
	InitiatorStaticKey          utils.HexBinary   `json:"init_static"`
	InitiatorRemoteEphemeralKey utils.HexBinary   `json:"init_remote_ephemeral"`
	InitiatorRemoteStaticKey    utils.HexBinary   `json:"init_remote_static"`
	InitiatorPsks               []utils.HexBinary `json:"init_psks"`
	ResponderPrologue           utils.HexBinary   `json:"resp_prologue"`
	ResponderEphemeralKey       utils.HexBinary   `json:"resp_ephemeral"`
	ResponderStaticKey          utils.HexBinary   `json:"resp_static"`
	ResponderRemoteEphemeralKey utils.HexBinary   `json:"resp_remote_ephemeral"`
	ResponderRemoteStaticKey    utils.HexBinary   `json:"resp_remote_static"`
	ResponderPsks               []utils.HexBinary `json:"resp_psks"`
	HandshakeHash               utils.HexBinary   `json:"handshake_hash"`
	Messages                    []TestMessage     `json:"messages"`
}

TestVector holds noise protocol test vector fields.

func LoadTestVectors

func LoadTestVectors(srcpath string) ([]TestVector, error)

LoadTestVector loads test vectors from json file at srcpath.

type TransportCipher

type TransportCipher struct {
	CipherState
}

TransportCipher is a CipherState that is used after handshake completion.

func (*TransportCipher) DecryptWithAd

func (self *TransportCipher) DecryptWithAd(ad, ciphertext []byte) ([]byte, error)

DecryptWithAd performs authenticated decryption of ciphertext if the TransportCipher has a key otherwise it errors.

The ad parameter maybe nil, it shall match the ad used for obtaining ciphertext. ad corresponds to AEAD "additional data" and it was used alongside plaintext and key to calculate the ciphertext authentication tag.

The noise protocol specs suggests using CipherState.DecryptWithAd for transport decryption. The problem is that CipherState allows operating with a zero key which is necessary for starting the handshake, but would be insecure during the transport phase.

func (*TransportCipher) EncryptWithAd

func (self *TransportCipher) EncryptWithAd(ad, plaintext []byte) ([]byte, error)

EncryptWithAd performs authenticated encryption of plaintext if the TransportCipher has a key otherwise it errors.

The ad parameter maybe nil, it corresponds to AEAD "additional data" and it is used alongside plaintext and key to calculate the ciphertext authentication tag.

The noise protocol specs suggests using CipherState.EncryptWithAd for transport encryption. The problem is that CipherState allows operating with a zero key which is necessary for starting the handshake, but would be insecure during the transport phase.

type TransportCipherPair

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

TransportCipherPair holds TransportCipher used for transport encryption/decryption.

func (*TransportCipherPair) Decryptor

func (self *TransportCipherPair) Decryptor() *TransportCipher

Decryptor returns the TransportCipher to be used for transport decryption.

func (*TransportCipherPair) Encryptor

func (self *TransportCipherPair) Encryptor() *TransportCipher

Encryptor returns the TransportCipher to be used for transport encryption.

type VerifierProvider

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

VerifierProvider holds CredentialVerifiers to be used in a noise protocol handshake.

func (*VerifierProvider) Get

func (self *VerifierProvider) Get(name string) CredentialVerifier

Get returns the CredentialVerifier that corresponds to name if any.

func (*VerifierProvider) Reset

func (self *VerifierProvider) Reset()

Reset resets all the CredentialVerifier in the VerifierProvider.

It is safe to call Reset on a nil VerifierProvider.

func (*VerifierProvider) SetLoaders

func (self *VerifierProvider) SetLoaders(names ...string)

SetLoaders allows declaring which HandshakeState credentials (eg psks, password...) are loaded by the verifiers registered with the VerifierProvider.

func (*VerifierProvider) SetVerifier

func (self *VerifierProvider) SetVerifier(name string, cv CredentialVerifier)

SetVerifier registers a CredentialVerifier with the VerifierProvider.

registration name normally corresponds to HandshakePattern tokens eg "s", "rs"...

This implementation of VerifierProvider supports registering at most 2 CredentialVerifiers. A static key verifier that can be registered with names "s" or "rs". An "extension" verifier that can be registered with any other name.

func (*VerifierProvider) ShouldLoad

func (self *VerifierProvider) ShouldLoad(name string) bool

ShouldLoad returns true if name corresponds to a loader registered with the VerifierProvider.

Jump to

Keyboard shortcuts

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