crypto

package
v0.0.0-...-72e6a2b Latest Latest
Warning

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

Go to latest
Published: Dec 24, 2025 License: MIT Imports: 17 Imported by: 0

README

crypto

Package crypto provides the core cryptographic primitives required by the Matter protocol.

It wraps standard Go crypto libraries and implements Matter-specific algorithms where necessary (e.g., SPAKE2+, privacy nonce construction).

Features

  • AES-CCM-128: Authenticated encryption for message payloads (Spec 3.6).
  • HKDF-SHA256: Key derivation for session keys (Spec 3.8).
  • NIST P-256: Elliptic curve for signatures and ECDH (Spec 3.4).
  • SPAKE2+: Password-Authenticated Key Exchange for commissioning (Spec 3.10).

Usage

This package is primarily a utility library for pkg/session and pkg/securechannel.

Authenticated Encryption
import "github.com/backkem/matter/pkg/crypto"

// Encrypt (Key must be 16 bytes)
ciphertext, err := crypto.AESCCM128Encrypt(key, nonce, plaintext, aad)

// Decrypt
plaintext, err := crypto.AESCCM128Decrypt(key, nonce, ciphertext, aad)
Key Derivation
// Derive keys using HKDF-SHA256
key := crypto.HKDF_SHA256(secret, salt, info, outputLen)

Documentation

Overview

Package crypto provides cryptographic primitives for the Matter protocol. This implements the cryptographic functions defined in Matter Specification Chapter 3.

Index

Constants

View Source
const (
	// AESCCMKeySize is the AES-128 key size in bytes (CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES).
	AESCCMKeySize = 16

	// AESCCMTagSize is the authentication tag size in bytes (CRYPTO_AEAD_MIC_LENGTH_BYTES).
	// Matter mandates 128-bit tags.
	AESCCMTagSize = 16

	// AESCCMNonceSize is the nonce size in bytes (CRYPTO_AEAD_NONCE_LENGTH_BYTES).
	// Matter mandates 13-byte nonces.
	AESCCMNonceSize = 13
)

AES-CCM constants from Matter Specification Section 3.6.

View Source
const (
	// AESCTRKeySize is the AES-128 key size in bytes.
	AESCTRKeySize = 16

	// AESCTRNonceSize is the nonce size in bytes (CRYPTO_PRIVACY_NONCE_LENGTH_BYTES).
	// Matter mandates 13-byte nonces for privacy encryption.
	AESCTRNonceSize = 13
)

AES-CTR constants from Matter Specification Section 3.7.

View Source
const (
	// CompressedFabricIDSize is the size of compressed fabric identifier (8 bytes).
	CompressedFabricIDSize = 8

	// GroupSessionIDSize is the size of the group session ID (2 bytes).
	GroupSessionIDSize = 2
)

Group key derivation constants.

View Source
const (
	// SHA256LenBits is the SHA-256 output length in bits (CRYPTO_HASH_LEN_BITS).
	SHA256LenBits = 256

	// SHA256LenBytes is the SHA-256 output length in bytes (CRYPTO_HASH_LEN_BYTES).
	SHA256LenBytes = 32
)

SHA-256 constants from Matter Specification Section 3.3.

View Source
const (
	// PBKDF2IterationsMin is the minimum allowed iterations (CRYPTO_PBKDF_ITERATIONS_MIN).
	PBKDF2IterationsMin = 1000

	// PBKDF2IterationsMax is the maximum allowed iterations (CRYPTO_PBKDF_ITERATIONS_MAX).
	PBKDF2IterationsMax = 100000
)

PBKDF2 iteration limits from Matter Specification Section 3.9.

View Source
const (
	// NonceSize is the AEAD nonce length (CRYPTO_AEAD_NONCE_LENGTH_BYTES).
	// Used for both AES-CCM message encryption and AES-CTR privacy encryption.
	NonceSize = 13

	// SymmetricKeySize is the symmetric key length (CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES).
	SymmetricKeySize = 16

	// MICSize is the Message Integrity Check length (CRYPTO_AEAD_MIC_LENGTH_BYTES).
	MICSize = 16

	// PrivacyNonceMICOffset is the starting offset in the MIC for privacy nonce (5).
	PrivacyNonceMICOffset = 5

	// PrivacyNonceMICLength is the length of MIC fragment used in privacy nonce (11).
	PrivacyNonceMICLength = 11
)

Message security constants from Matter Specification.

View Source
const (
	// P256GroupSizeBits is the group size in bits (CRYPTO_GROUP_SIZE_BITS).
	P256GroupSizeBits = 256

	// P256GroupSizeBytes is the group size in bytes (CRYPTO_GROUP_SIZE_BYTES).
	P256GroupSizeBytes = 32

	// P256PublicKeySizeBytes is the uncompressed public key size (CRYPTO_PUBLIC_KEY_SIZE_BYTES).
	// Format: 0x04 || X (32 bytes) || Y (32 bytes) = 65 bytes
	P256PublicKeySizeBytes = 65

	// P256CompressedPublicKeySizeBytes is the compressed public key size.
	// Format: 0x02/0x03 || X (32 bytes) = 33 bytes
	P256CompressedPublicKeySizeBytes = 33

	// P256SignatureSizeBytes is the signature size (r || s).
	P256SignatureSizeBytes = 64
)

P-256 constants from Matter Specification Section 3.5.1.

Variables

View Source
var (
	ErrAESCCMInvalidKeySize     = errors.New("aesccm: invalid key size, must be 16 bytes")
	ErrAESCCMInvalidNonceSize   = errors.New("aesccm: invalid nonce size")
	ErrAESCCMInvalidTagSize     = errors.New("aesccm: invalid tag size, must be 4, 6, 8, 10, 12, 14, or 16")
	ErrAESCCMPlaintextTooLong   = errors.New("aesccm: plaintext too long")
	ErrAESCCMCiphertextTooShort = errors.New("aesccm: ciphertext too short")
	ErrAESCCMAuthFailed         = errors.New("aesccm: message authentication failed")
)

Errors

View Source
var (
	ErrAESCTRInvalidKeySize   = errors.New("aesctr: invalid key size, must be 16 bytes")
	ErrAESCTRInvalidNonceSize = errors.New("aesctr: invalid nonce size, must be 13 bytes")
)

Errors for AES-CTR operations.

View Source
var (
	ErrInvalidEpochKeySize           = errors.New("group: invalid epoch key size, must be 16 bytes")
	ErrInvalidCompressedFabricIDSize = errors.New("group: invalid compressed fabric ID size, must be 8 bytes")
	ErrInvalidOperationalKeySize     = errors.New("group: invalid operational key size, must be 16 bytes")
)

Errors for group key operations.

View Source
var (
	ErrInvalidKeySize = errors.New("nonce: invalid key size, must be 16 bytes")
	ErrInvalidMICSize = errors.New("nonce: invalid MIC size, must be 16 bytes")
)

Errors for nonce operations.

Functions

func AESCCM128Decrypt

func AESCCM128Decrypt(key, nonce, ciphertext, aad []byte) ([]byte, error)

AESCCM128Decrypt is a convenience function for AES-128-CCM decryption. This implements Crypto_AEAD_DecryptVerify from Matter Specification Section 3.6.2.

Parameters:

  • key: 16-byte AES-128 key
  • nonce: 13-byte nonce
  • ciphertext: encrypted data with tag
  • aad: additional authenticated data

Returns the decrypted plaintext, or an error if authentication fails.

func AESCCM128Encrypt

func AESCCM128Encrypt(key, nonce, plaintext, aad []byte) ([]byte, error)

AESCCM128Encrypt is a convenience function for AES-128-CCM encryption. This implements Crypto_AEAD_GenerateEncrypt from Matter Specification Section 3.6.1.

Parameters:

  • key: 16-byte AES-128 key
  • nonce: 13-byte nonce
  • plaintext: data to encrypt
  • aad: additional authenticated data

Returns ciphertext || tag.

func AESCTRDecrypt

func AESCTRDecrypt(key, nonce, ciphertext []byte) ([]byte, error)

AESCTRDecrypt is a convenience function for AES-128-CTR decryption. This implements Crypto_Privacy_Decrypt from Matter Specification Section 3.7.2.

Parameters:

  • key: 16-byte AES-128 key
  • nonce: 13-byte nonce
  • ciphertext: data to decrypt

Returns plaintext of the same length as ciphertext.

func AESCTREncrypt

func AESCTREncrypt(key, nonce, plaintext []byte) ([]byte, error)

AESCTREncrypt is a convenience function for AES-128-CTR encryption. This implements Crypto_Privacy_Encrypt from Matter Specification Section 3.7.1.

Parameters:

  • key: 16-byte AES-128 key
  • nonce: 13-byte nonce
  • plaintext: data to encrypt

Returns ciphertext of the same length as plaintext.

func BuildAEADNonce

func BuildAEADNonce(securityFlags uint8, messageCounter uint32, sourceNodeID uint64) []byte

BuildAEADNonce constructs a 13-byte nonce for AEAD encryption/decryption. This implements the nonce format from Matter Specification Section 4.8.1.1 (Table 17).

Format: SecurityFlags (1 byte) || MessageCounter (4 bytes LE) || SourceNodeID (8 bytes LE)

Parameters:

  • securityFlags: Security flags byte from the message header
  • messageCounter: Message counter (32-bit, little-endian in nonce)
  • sourceNodeID: Source node ID (64-bit, little-endian in nonce) For PASE sessions, use UnspecifiedNodeID (0). For CASE sessions, use the Operational Node ID. For Group sessions, use the Source Node ID from the message.

Returns a 13-byte nonce suitable for AES-CCM operations.

func BuildPrivacyNonce

func BuildPrivacyNonce(sessionID uint16, mic []byte) ([]byte, error)

BuildPrivacyNonce constructs a 13-byte nonce for privacy encryption/decryption. This implements Section 4.9.2 "Privacy Nonce".

Format: SessionID (2 bytes BE) || MIC[5..15] (11 bytes)

The privacy nonce uses the session ID in big-endian format concatenated with the lower 11 bytes of the MIC (bytes at indices 5 through 15 inclusive).

Parameters:

  • sessionID: The 16-bit session identifier
  • mic: The 16-byte Message Integrity Check (tag) from AEAD encryption

Returns a 13-byte nonce suitable for AES-CTR privacy operations.

func DeriveGroupOperationalKeyV1

func DeriveGroupOperationalKeyV1(epochKey, compressedFabricID []byte) ([]byte, error)

DeriveGroupOperationalKeyV1 derives an operational group key from an epoch key. This implements Section 4.17.2 "Operational Group Key Derivation" using the "GroupKey v1.0" info string. Future protocol versions may use different info strings.

OperationalGroupKey = HKDF-SHA256(

InputKey = EpochKey,
Salt = CompressedFabricIdentifier,
Info = "GroupKey v1.0",
Length = CRYPTO_SYMMETRIC_KEY_LENGTH_BITS

)

Parameters:

  • epochKey: The 16-byte epoch key from a group key set
  • compressedFabricID: The 8-byte compressed fabric identifier

Returns the 16-byte operational group key used for message encryption.

func DeriveGroupSessionIDV1

func DeriveGroupSessionIDV1(operationalKey []byte) (uint16, error)

DeriveGroupSessionIDV1 derives a group session ID from an operational group key. This is used to identify messages encrypted with a particular group key. Uses HKDF-SHA256 with "GroupKeyHash" info string.

GKH = HKDF-SHA256(

InputKey = OperationalGroupKey,
Salt = [],
Info = "GroupKeyHash",
Length = 2

) GroupSessionID = BigEndian.Get16(GKH[0:2])

Parameters:

  • operationalKey: The 16-byte operational group key

Returns the 16-bit group session ID.

func DerivePrivacyKey

func DerivePrivacyKey(encryptionKey []byte) ([]byte, error)

DerivePrivacyKey derives a privacy key from an encryption key. This implements Section 4.9.1 "Privacy Key" derivation.

PrivacyKey = Crypto_KDF(

InputKey = EncryptionKey,
Salt = [],
Info = "PrivacyKey",
Length = CRYPTO_SYMMETRIC_KEY_LENGTH_BITS

)

Parameters:

  • encryptionKey: The 16-byte session encryption key

Returns the 16-byte privacy key for use with AES-CTR privacy encryption.

func HKDFExpandSHA256

func HKDFExpandSHA256(prk, info []byte, length int) ([]byte, error)

HKDFExpandSHA256 performs only the HKDF-Expand operation. This expands a pseudorandom key into output keying material.

Parameters:

  • prk: Pseudorandom key (from HKDFExtract or other source)
  • info: Optional context/application-specific info
  • length: Number of bytes to derive

Returns the derived key material.

func HKDFExtractSHA256

func HKDFExtractSHA256(inputKey, salt []byte) []byte

HKDFExtractSHA256 performs only the HKDF-Extract operation. This extracts a pseudorandom key (PRK) from the input keying material.

Parameters:

  • inputKey: Input keying material (IKM)
  • salt: Optional salt value (can be nil, defaults to zero-filled HashLen bytes)

Returns a 32-byte pseudorandom key.

func HKDFSHA256

func HKDFSHA256(inputKey, salt, info []byte, length int) ([]byte, error)

HKDFSHA256 derives key material using HKDF-SHA256 (RFC 5869). This implements Crypto_KDF() from Matter Specification Section 3.8.

Parameters:

  • inputKey: Input keying material (IKM)
  • salt: Optional salt value (can be nil or empty)
  • info: Optional context/application-specific info (can be nil or empty)
  • length: Number of bytes to derive

Returns the derived key material of the specified length.

func HMACEqual

func HMACEqual(mac1, mac2 []byte) bool

HMACEqual compares two MACs for equality in constant time. This should be used instead of bytes.Equal to prevent timing attacks.

func HMACSHA256

func HMACSHA256(key, message []byte) [SHA256LenBytes]byte

HMACSHA256 computes the HMAC-SHA256 of a message using the given key. This implements Crypto_HMAC() from Matter Specification Section 3.4.

Returns a 32-byte (256-bit) MAC.

func HMACSHA256Slice

func HMACSHA256Slice(key, message []byte) []byte

HMACSHA256Slice computes the HMAC-SHA256 and returns it as a slice. This is a convenience function for cases where a slice is preferred.

func NewHMACSHA256

func NewHMACSHA256(key []byte) hash.Hash

NewHMACSHA256 returns a new hash.Hash for computing HMAC-SHA256 incrementally. This is useful for computing MACs over streaming data.

Usage:

h := crypto.NewHMACSHA256(key)
h.Write(data1)
h.Write(data2)
mac := h.Sum(nil)

func NewSHA256

func NewSHA256() hash.Hash

NewSHA256 returns a new hash.Hash for computing SHA-256 digests incrementally. This is useful for hashing large data or streaming data.

Usage:

h := crypto.NewSHA256()
h.Write(data1)
h.Write(data2)
digest := h.Sum(nil)

func P256ECDH

func P256ECDH(keyPair *P256KeyPair, peerPublicKey []byte) ([]byte, error)

P256ECDH computes the ECDH shared secret. This implements Crypto_ECDH() from Matter Specification Section 3.5.4.

Parameters:

  • keyPair: Our private key
  • peerPublicKey: Peer's 65-byte uncompressed public key (0x04 || X || Y)

Returns the 32-byte shared secret (x-coordinate of the shared point).

func P256ECDHFromPrivateKey

func P256ECDHFromPrivateKey(privateKey, peerPublicKey []byte) ([]byte, error)

P256ECDHFromPrivateKey computes ECDH using raw private key bytes. This is a convenience function when you have the private key as bytes.

func P256PublicKeyFromCompressed

func P256PublicKeyFromCompressed(compressed []byte) ([]byte, error)

P256PublicKeyFromCompressed decompresses a compressed public key. Input: 33-byte compressed key (0x02/0x03 || X) Output: 65-byte uncompressed key (0x04 || X || Y)

func P256Sign

func P256Sign(keyPair *P256KeyPair, message []byte) ([]byte, error)

P256Sign signs a message using ECDSA with SHA-256. This implements Crypto_Sign() from Matter Specification Section 3.5.3.

The message is hashed internally using SHA-256 before signing. Returns a 64-byte signature (r || s), each component zero-padded to 32 bytes.

func P256ValidatePublicKey

func P256ValidatePublicKey(publicKey []byte) error

P256ValidatePublicKey validates that a public key is valid and on the curve.

func P256Verify

func P256Verify(publicKey, message, signature []byte) (bool, error)

P256Verify verifies an ECDSA signature on a message. This implements Crypto_Verify() from Matter Specification Section 3.5.3.

Parameters:

  • publicKey: 65-byte uncompressed public key (0x04 || X || Y)
  • message: The original message that was signed
  • signature: 64-byte signature (r || s)

Returns true if the signature is valid, false otherwise.

func PBKDF2SHA256

func PBKDF2SHA256(password, salt []byte, iterations, keyLen int) []byte

PBKDF2SHA256 derives a key from a password using PBKDF2-HMAC-SHA256 (NIST 800-132). This implements Crypto_PBKDF() from Matter Specification Section 3.9.

Parameters:

  • password: The password/passcode to derive from
  • salt: Salt value (Matter requires 16-32 bytes)
  • iterations: Number of iterations (Matter: 1000-100000)
  • keyLen: Number of bytes to derive

Returns the derived key material.

func SHA256

func SHA256(message []byte) [SHA256LenBytes]byte

SHA256 computes the SHA-256 cryptographic hash of a message. This implements Crypto_Hash() from Matter Specification Section 3.3.

Returns a 32-byte (256-bit) hash digest.

func SHA256Slice

func SHA256Slice(message []byte) []byte

SHA256Slice computes the SHA-256 hash and returns it as a slice. This is a convenience function for cases where a slice is preferred.

Types

type AESCCM

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

AESCCM represents an AES-128-CCM cipher instance with configurable parameters.

func NewAESCCM

func NewAESCCM(key []byte) (*AESCCM, error)

NewAESCCM creates a new AES-128-CCM cipher with Matter-compliant parameters. The key must be exactly 16 bytes (128 bits). Uses 13-byte nonce and 16-byte tag as required by Matter Specification Section 3.6.

func NewAESCCMWithParams

func NewAESCCMWithParams(key []byte, nonceSize, tagSize int) (*AESCCM, error)

NewAESCCMWithParams creates a new AES-128-CCM cipher with configurable parameters. This allows testing with RFC 3610 vectors which use different nonce and tag sizes.

Parameters:

  • key: 16-byte AES-128 key
  • nonceSize: nonce length in bytes (7-13 per NIST 800-38C)
  • tagSize: authentication tag length in bytes (4, 6, 8, 10, 12, 14, or 16)

func (*AESCCM) NonceSize

func (c *AESCCM) NonceSize() int

NonceSize returns the required nonce size for this cipher.

func (*AESCCM) Open

func (c *AESCCM) Open(nonce, ciphertext, aad []byte) ([]byte, error)

Open decrypts and verifies ciphertext with associated data. This implements Crypto_AEAD_DecryptVerify from Matter Specification Section 3.6.2.

Parameters:

  • nonce: nonce of the configured size (same as used for encryption)
  • ciphertext: encrypted data with tag (minimum tagSize bytes for tag)
  • aad: additional authenticated data

Returns the decrypted plaintext, or an error if authentication fails.

func (*AESCCM) Seal

func (c *AESCCM) Seal(nonce, plaintext, aad []byte) ([]byte, error)

Seal encrypts and authenticates plaintext with associated data. This implements Crypto_AEAD_GenerateEncrypt from Matter Specification Section 3.6.1.

Parameters:

  • nonce: nonce of the configured size (must be unique for each encryption with the same key)
  • plaintext: data to encrypt
  • aad: additional authenticated data (not encrypted, but authenticated)

Returns ciphertext || tag (plaintext length + tagSize bytes for tag).

func (*AESCCM) TagSize

func (c *AESCCM) TagSize() int

TagSize returns the authentication tag size for this cipher.

type AESCTR

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

AESCTR represents an AES-128-CTR cipher instance for privacy encryption.

func NewAESCTR

func NewAESCTR(key []byte) (*AESCTR, error)

NewAESCTR creates a new AES-128-CTR cipher for Matter privacy encryption. The key must be exactly 16 bytes (128 bits).

func (*AESCTR) Decrypt

func (c *AESCTR) Decrypt(nonce, ciphertext []byte) ([]byte, error)

Decrypt decrypts ciphertext using AES-CTR mode. This implements Crypto_Privacy_Decrypt from Matter Specification Section 3.7.2.

Parameters:

  • nonce: 13-byte nonce (same as used for encryption)
  • ciphertext: data to decrypt

Returns plaintext of the same length as ciphertext.

func (*AESCTR) Encrypt

func (c *AESCTR) Encrypt(nonce, plaintext []byte) ([]byte, error)

Encrypt encrypts plaintext using AES-CTR mode. This implements Crypto_Privacy_Encrypt from Matter Specification Section 3.7.1.

Parameters:

  • nonce: 13-byte nonce
  • plaintext: data to encrypt

Returns ciphertext of the same length as plaintext.

func (*AESCTR) NonceSize

func (c *AESCTR) NonceSize() int

NonceSize returns the required nonce size for this cipher.

type GroupOperationalCredentials

type GroupOperationalCredentials struct {
	// EncryptionKey is the 16-byte operational group key for AES-CCM encryption.
	EncryptionKey []byte

	// PrivacyKey is the 16-byte privacy key for AES-CTR privacy encryption.
	PrivacyKey []byte

	// SessionID is the 16-bit group session ID.
	SessionID uint16
}

GroupOperationalCredentials holds all derived credentials for a group.

func DeriveGroupCredentialsV1

func DeriveGroupCredentialsV1(epochKey, compressedFabricID []byte) (*GroupOperationalCredentials, error)

DeriveGroupCredentialsV1 derives all group operational credentials from an epoch key. This is a convenience function that combines DeriveGroupOperationalKeyV1, DerivePrivacyKey, and DeriveGroupSessionIDV1.

Parameters:

  • epochKey: The 16-byte epoch key from a group key set
  • compressedFabricID: The 8-byte compressed fabric identifier

Returns a GroupOperationalCredentials struct with all derived keys and session ID.

type P256KeyPair

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

P256KeyPair represents a P-256 key pair. This implements the KeyPair type from Matter Specification Section 3.5.1.

func P256GenerateKeyPair

func P256GenerateKeyPair() (*P256KeyPair, error)

P256GenerateKeyPair generates a new P-256 key pair. This implements Crypto_GenerateKeyPair() from Matter Specification Section 3.5.2.

func P256KeyPairFromPrivateKey

func P256KeyPairFromPrivateKey(privateKey []byte) (*P256KeyPair, error)

P256KeyPairFromPrivateKey creates a key pair from an existing private key scalar.

func (*P256KeyPair) P256PrivateKey

func (kp *P256KeyPair) P256PrivateKey() []byte

P256PrivateKey returns the private key as a 32-byte scalar.

func (*P256KeyPair) P256PublicKey

func (kp *P256KeyPair) P256PublicKey() []byte

P256PublicKey returns the public key in uncompressed format (65 bytes). Format: 0x04 || X (32 bytes) || Y (32 bytes)

func (*P256KeyPair) P256PublicKeyCompressed

func (kp *P256KeyPair) P256PublicKeyCompressed() []byte

P256PublicKeyCompressed returns the public key in compressed format (33 bytes). Format: 0x02 (even Y) or 0x03 (odd Y) || X (32 bytes)

Directories

Path Synopsis
Package spake2p implements the SPAKE2+ Password-Authenticated Key Exchange protocol.
Package spake2p implements the SPAKE2+ Password-Authenticated Key Exchange protocol.

Jump to

Keyboard shortcuts

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