protocol

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 14, 2026 License: AGPL-3.0 Imports: 9 Imported by: 0

Documentation

Overview

Package protocol implements the Signal wire message types: the versioned, length-checked binary encodings of SignalMessage, PreKeySignalMessage, and the group/plaintext message forms. It is a pure-Go port of rust/protocol/src/protocol.rs and is wire-compatible with upstream libsignal.

Index

Constants

View Source
const (
	// CurrentVersion is the current ciphertext message version (PQXDH / v4).
	CurrentVersion uint8 = 4
	// PreKyberVersion is the last version without Kyber keys (v3). Messages at
	// this version are still accepted on deserialize for backward compatibility.
	PreKyberVersion uint8 = 3
	// SenderKeyCurrentVersion is the current SenderKeyMessage version
	// (SENDERKEY_MESSAGE_CURRENT_VERSION in protocol.rs). The sender-key message
	// family versions independently of the Double Ratchet messages.
	SenderKeyCurrentVersion uint8 = 3
)

Ciphertext message version constants, from rust/protocol/src/protocol.rs.

View Source
const (
	// MessageTypeWhisper tags a SignalMessage.
	MessageTypeWhisper uint8 = 2
	// MessageTypePreKey tags a PreKeySignalMessage.
	MessageTypePreKey uint8 = 3
	// MessageTypeSenderKey tags a SenderKeyMessage.
	MessageTypeSenderKey uint8 = 7
	// MessageTypePlaintext tags a PlaintextContent message.
	MessageTypePlaintext uint8 = 8
)

Ciphertext message type tags, from CiphertextMessageType in protocol.rs.

Variables

View Source
var (
	// ErrCiphertextTooShort is returned when a serialized message is shorter
	// than its minimum framing (version byte, and for SignalMessage the MAC).
	ErrCiphertextTooShort = errors.New("protocol: ciphertext message too short")
	// ErrLegacyVersion is returned when a message declares a version below the
	// minimum supported version (PreKyberVersion).
	ErrLegacyVersion = errors.New("protocol: legacy ciphertext version")
	// ErrUnrecognizedVersion is returned when a message declares a version
	// above CurrentVersion.
	ErrUnrecognizedVersion = errors.New("protocol: unrecognized ciphertext version")
	// ErrInvalidProtobuf is returned when the protobuf body fails to decode or
	// is missing a required field.
	ErrInvalidProtobuf = errors.New("protocol: invalid protobuf encoding")
	// ErrInvalidMACKeyLength is returned when a MAC key is not 32 bytes.
	ErrInvalidMACKeyLength = errors.New("protocol: invalid MAC key length")
	// ErrInvalidMessage is returned when a message is structurally valid but
	// semantically rejected (e.g. a v4 PreKeySignalMessage missing its Kyber
	// payload).
	ErrInvalidMessage = errors.New("protocol: invalid message")
)

Errors returned by this package. All are sentinel errors matchable with errors.Is; call sites return them either directly or %w-wrapped with context.

Functions

This section is empty.

Types

type DecryptionErrorMessage

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

DecryptionErrorMessage reports a failed decryption back to the sender. Its wire form is the bare protobuf encoding (no version byte).

func DeserializeDecryptionErrorMessage

func DeserializeDecryptionErrorMessage(value []byte) (*DecryptionErrorMessage, error)

DeserializeDecryptionErrorMessage parses the protobuf wire form. The timestamp field is required; ratchet_key is optional and device_id defaults to 0.

func NewDecryptionErrorMessage

func NewDecryptionErrorMessage(
	ratchetKey *curve.PublicKey,
	timestamp uint64,
	deviceID uint32,
) (*DecryptionErrorMessage, error)

NewDecryptionErrorMessage builds a DecryptionErrorMessage. ratchetKey is the public ratchet key from the message that failed to decrypt, or nil when the original message type carries none (e.g. a sender-key message).

func (*DecryptionErrorMessage) DeviceID

func (m *DecryptionErrorMessage) DeviceID() uint32

DeviceID returns the original sender device ID.

func (*DecryptionErrorMessage) RatchetKey

func (m *DecryptionErrorMessage) RatchetKey() *curve.PublicKey

RatchetKey returns the ratchet public key, or nil if the message carries none.

func (*DecryptionErrorMessage) Serialized

func (m *DecryptionErrorMessage) Serialized() []byte

Serialized returns the protobuf wire encoding.

func (*DecryptionErrorMessage) Timestamp

func (m *DecryptionErrorMessage) Timestamp() uint64

Timestamp returns the original message timestamp (epoch milliseconds).

type PlaintextContent

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

PlaintextContent is a message that may be sent without encryption. Its wire form is the identifier byte (0xC0), a Content protobuf body, and a trailing padding-boundary byte (0x80).

func DeserializePlaintextContent

func DeserializePlaintextContent(value []byte) (*PlaintextContent, error)

DeserializePlaintextContent parses the wire form, requiring the leading identifier byte. The body is not further decoded here (it mirrors upstream, which stores the serialized form and exposes the body via Body).

func NewPlaintextContentFromDecryptionError

func NewPlaintextContentFromDecryptionError(message *DecryptionErrorMessage) (*PlaintextContent, error)

NewPlaintextContentFromDecryptionError wraps a DecryptionErrorMessage as PlaintextContent, matching the upstream From<DecryptionErrorMessage> conversion.

func (*PlaintextContent) Body

func (m *PlaintextContent) Body() []byte

Body returns the message contents after the identifier byte.

func (*PlaintextContent) Serialized

func (m *PlaintextContent) Serialized() []byte

Serialized returns the full wire encoding.

type PreKeySignalMessage

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

PreKeySignalMessage is the initial message of a session, carrying the prekey identifiers and the keys needed to establish the ratchet, wrapping an inner SignalMessage. Its wire form is: version byte ‖ protobuf body (no MAC; the inner SignalMessage carries its own MAC).

func DeserializePreKeySignalMessage

func DeserializePreKeySignalMessage(value []byte) (*PreKeySignalMessage, error)

DeserializePreKeySignalMessage parses and validates the wire form. It checks the version range, decodes the body (requiring base key, identity key, inner message, and signed-prekey id), enforces the Kyber-payload rule (required for versions above PreKyberVersion; both-or-neither otherwise), and recursively parses the inner SignalMessage. Mirrors PreKeySignalMessage::try_from.

func NewPreKeySignalMessage

func NewPreKeySignalMessage(
	messageVersion uint8,
	registrationID uint32,
	preKeyID *uint32,
	signedPreKeyID uint32,
	kyberPreKeyID *uint32,
	kyberCiphertext []byte,
	baseKey curve.PublicKey,
	identityKey curve.PublicKey,
	message *SignalMessage,
) (*PreKeySignalMessage, error)

NewPreKeySignalMessage builds and serializes a PreKeySignalMessage. A Kyber payload (kyberPreKeyID + kyberCiphertext) is required for v4 sessions; pass a nil preKeyID when there is no one-time prekey. The message is the inner SignalMessage. Mirrors PreKeySignalMessage::new.

func (*PreKeySignalMessage) BaseKey

func (m *PreKeySignalMessage) BaseKey() curve.PublicKey

BaseKey returns the sender's base public key.

func (*PreKeySignalMessage) IdentityKey

func (m *PreKeySignalMessage) IdentityKey() curve.PublicKey

IdentityKey returns the sender's identity public key.

func (*PreKeySignalMessage) KyberCiphertext

func (m *PreKeySignalMessage) KyberCiphertext() []byte

KyberCiphertext returns the Kyber ciphertext, or nil if no Kyber payload.

func (*PreKeySignalMessage) KyberPreKeyID

func (m *PreKeySignalMessage) KyberPreKeyID() *uint32

KyberPreKeyID returns the Kyber prekey id, or nil if no Kyber payload.

func (*PreKeySignalMessage) Message

func (m *PreKeySignalMessage) Message() *SignalMessage

Message returns the inner SignalMessage.

func (*PreKeySignalMessage) MessageVersion

func (m *PreKeySignalMessage) MessageVersion() uint8

MessageVersion returns the message's protocol version.

func (*PreKeySignalMessage) PreKeyID

func (m *PreKeySignalMessage) PreKeyID() *uint32

PreKeyID returns the one-time prekey id, or nil if the message used none.

func (*PreKeySignalMessage) RegistrationID

func (m *PreKeySignalMessage) RegistrationID() uint32

RegistrationID returns the sender's registration id.

func (*PreKeySignalMessage) Serialize

func (m *PreKeySignalMessage) Serialize() []byte

Serialize returns the full wire form (version byte ‖ body).

func (*PreKeySignalMessage) SignedPreKeyID

func (m *PreKeySignalMessage) SignedPreKeyID() uint32

SignedPreKeyID returns the signed prekey id.

type SenderKeyDistributionMessage

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

SenderKeyDistributionMessage announces a sender-key chain to group members. Its wire form is a version byte followed by the protobuf body; it carries no signature.

func DeserializeSenderKeyDistributionMessage

func DeserializeSenderKeyDistributionMessage(value []byte) (*SenderKeyDistributionMessage, error)

DeserializeSenderKeyDistributionMessage parses the wire form of a SenderKeyDistributionMessage.

func NewSenderKeyDistributionMessage

func NewSenderKeyDistributionMessage(
	distributionID [uuidLen]byte,
	chainID uint32,
	iteration uint32,
	chainKey []byte,
	signingKey curve.PublicKey,
) (*SenderKeyDistributionMessage, error)

NewSenderKeyDistributionMessage builds a SenderKeyDistributionMessage.

func (*SenderKeyDistributionMessage) ChainID

func (m *SenderKeyDistributionMessage) ChainID() uint32

ChainID returns the chain ID.

func (*SenderKeyDistributionMessage) ChainKey

func (m *SenderKeyDistributionMessage) ChainKey() []byte

ChainKey returns the chain key.

func (*SenderKeyDistributionMessage) DistributionID

func (m *SenderKeyDistributionMessage) DistributionID() [uuidLen]byte

DistributionID returns the raw 16-byte distribution UUID.

func (*SenderKeyDistributionMessage) Iteration

func (m *SenderKeyDistributionMessage) Iteration() uint32

Iteration returns the iteration.

func (*SenderKeyDistributionMessage) MessageVersion

func (m *SenderKeyDistributionMessage) MessageVersion() uint8

MessageVersion returns the message version.

func (*SenderKeyDistributionMessage) Serialized

func (m *SenderKeyDistributionMessage) Serialized() []byte

Serialized returns the full wire encoding.

func (*SenderKeyDistributionMessage) SigningKey

SigningKey returns the signing public key.

type SenderKeyMessage

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

SenderKeyMessage is a group (sender-key) ciphertext message. Its wire form is a version byte, the protobuf body, and a trailing 64-byte XEdDSA signature computed over the version byte and body.

func DeserializeSenderKeyMessage

func DeserializeSenderKeyMessage(value []byte) (*SenderKeyMessage, error)

DeserializeSenderKeyMessage parses the wire form of a SenderKeyMessage, validating the version and protobuf body. It does not verify the signature; call VerifySignature for that.

func NewSenderKeyMessage

func NewSenderKeyMessage(
	distributionID [uuidLen]byte,
	chainID uint32,
	iteration uint32,
	ciphertext []byte,
	rng io.Reader,
	signatureKey curve.PrivateKey,
) (*SenderKeyMessage, error)

NewSenderKeyMessage builds and signs a SenderKeyMessage. The signature is an XEdDSA signature over the version byte and protobuf body, using signatureKey; rng supplies the signature nonce (use crypto/rand.Reader in production).

func (*SenderKeyMessage) ChainID

func (m *SenderKeyMessage) ChainID() uint32

ChainID returns the chain ID.

func (*SenderKeyMessage) Ciphertext

func (m *SenderKeyMessage) Ciphertext() []byte

Ciphertext returns the ciphertext body.

func (*SenderKeyMessage) DistributionID

func (m *SenderKeyMessage) DistributionID() [uuidLen]byte

DistributionID returns the raw 16-byte distribution UUID.

func (*SenderKeyMessage) Iteration

func (m *SenderKeyMessage) Iteration() uint32

Iteration returns the iteration.

func (*SenderKeyMessage) MessageVersion

func (m *SenderKeyMessage) MessageVersion() uint8

MessageVersion returns the message version.

func (*SenderKeyMessage) Serialized

func (m *SenderKeyMessage) Serialized() []byte

Serialized returns the full wire encoding.

func (*SenderKeyMessage) VerifySignature

func (m *SenderKeyMessage) VerifySignature(signatureKey curve.PublicKey) bool

VerifySignature reports whether the message's trailing signature is valid under signatureKey, computed over the version byte and protobuf body.

type SignalMessage

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

SignalMessage is the Double Ratchet ciphertext message ("Whisper" message). Its wire form is: version byte ‖ protobuf body ‖ HMAC-SHA256 tag[:8].

func DeserializeSignalMessage

func DeserializeSignalMessage(value []byte) (*SignalMessage, error)

DeserializeSignalMessage parses and validates the wire form of a SignalMessage. It checks the minimum length, the version range, and decodes the protobuf body, requiring the ratchet key, counter, and ciphertext fields. It does not verify the MAC; call VerifyMAC for that.

func NewSignalMessage

func NewSignalMessage(
	messageVersion uint8,
	macKey []byte,
	senderRatchetKey curve.PublicKey,
	counter uint32,
	previousCounter uint32,
	ciphertext []byte,
	senderIdentityKey curve.PublicKey,
	receiverIdentityKey curve.PublicKey,
	pqRatchet []byte,
	addresses []byte,
) (*SignalMessage, error)

NewSignalMessage builds and serializes a SignalMessage, computing the MAC over the sender/receiver identity public keys and the versioned body, exactly as SignalMessage::new in protocol.rs. macKey must be 32 bytes. pqRatchet may be nil/empty (it is then omitted from the proto, matching upstream). addresses may be nil.

func (*SignalMessage) Body

func (m *SignalMessage) Body() []byte

Body returns the inner ciphertext.

func (*SignalMessage) Counter

func (m *SignalMessage) Counter() uint32

Counter returns the message counter.

func (*SignalMessage) MessageVersion

func (m *SignalMessage) MessageVersion() uint8

MessageVersion returns the message's protocol version.

func (*SignalMessage) PQRatchet

func (m *SignalMessage) PQRatchet() []byte

PQRatchet returns the opaque SPQR state bytes (empty when absent).

func (*SignalMessage) PreviousCounter

func (m *SignalMessage) PreviousCounter() uint32

PreviousCounter returns the previous-chain counter.

func (*SignalMessage) SenderRatchetKey

func (m *SignalMessage) SenderRatchetKey() curve.PublicKey

SenderRatchetKey returns the sender's ratchet public key.

func (*SignalMessage) Serialize

func (m *SignalMessage) Serialize() []byte

Serialize returns the full wire form (version byte ‖ body ‖ MAC).

func (*SignalMessage) VerifyMAC

func (m *SignalMessage) VerifyMAC(senderIdentityKey, receiverIdentityKey curve.PublicKey, macKey []byte) (bool, error)

VerifyMAC recomputes the message's MAC from the identity keys and mac key and compares it (in constant time) against the trailing tag. It returns false on mismatch and an error only for a malformed mac key. Mirrors SignalMessage::verify_mac.

Jump to

Keyboard shortcuts

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