crypto

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2026 License: MPL-2.0 Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
const BlockSize = uint64(2 << 16) // Double the block size that linux cp uses.

Variables

View Source
var ErrNonceOverflow = errors.New("crypto: nonce counter overflow within an epoch (missing rekey)")

ErrNonceOverflow is returned by Next when the 48-bit per-epoch counter would wrap into the epoch bytes and reuse a (key, nonce) pair. The ratchet rotates far below 2^48 messages, so reaching this means rotation stalled; the caller closes that one connection.

Functions

func Decrypt

func Decrypt(kek, input []byte) ([]byte, error)

Decrypt decrypts [nonce | ciphertext+MAC] using KEK. Returns plainText or error if authentication fails.

func DecryptChunked

func DecryptChunked(kek []byte, r io.Reader, w io.Writer, cipherSize uint64) error

func DecryptWithAAD added in v0.2.0

func DecryptWithAAD(kek, input, aad []byte) ([]byte, error)

DecryptWithAAD decrypts [nonce | ciphertext+MAC] with KEK and verifies the associated data. The aad must match what EncryptWithAAD used, or authentication fails; pass nil when none was used. It returns plainText, or an error on authentication failure.

func DecryptedSize

func DecryptedSize(cipherSize uint64) (uint64, error)

func DeriveAES256Key

func DeriveAES256Key(sharedSecrets ...[]byte) ([]byte, error)

DeriveAES256Key derives a 32-byte symmetric key for AES-256-GCM. A different HKDF label keeps domain separation from ChaCha20 keys.

func DeriveChaCha20Key

func DeriveChaCha20Key(sharedSecrets ...[]byte) ([]byte, error)

DeriveChaCha20Key derives a 32-byte symmetric key using SHA-512 over the given secrets.

func DeriveFileEncryptionKey added in v0.2.0

func DeriveFileEncryptionKey(masterKey, salt []byte, info string) ([]byte, error)

DeriveFileEncryptionKey derives a 32-byte per-file AEAD key from a master key and a per-file salt via HKDF-SHA512. Each use case passes a distinct info string, such as "keibidrop-identity-file-v1" or "keibidrop-contacts-file-v1".

func DeriveFoldSalt added in v0.4.0

func DeriveFoldSalt(ikm []byte) ([]byte, error)

DeriveFoldSalt derives the 32-byte session-bound fold salt from the given IKM via HKDF-SHA512 under a distinct label. Both peers pass the same order-normalized SEK material, so they derive an identical salt and agree on the fold secret.

func DeriveKey

func DeriveKey(suite CipherSuite, sharedSecrets ...[]byte) ([]byte, error)

DeriveKey derives a symmetric key using the appropriate HKDF label for the cipher suite. Domain separation ensures the same input secrets produce different keys for different ciphers.

func DerivePresenceKey added in v0.2.0

func DerivePresenceKey(posterFingerprint, checkerFingerprint string) ([]byte, error)

DerivePresenceKey derives a directional presence token; the poster's fingerprint always comes first. The poster calls (own, peer) to POST; the checker calls (peer, own) to GET.

func DeriveRelayKeys

func DeriveRelayKeys(roomPassword []byte) (lookupKey []byte, encryptionKey []byte, err error)

DeriveRelayKeys derives lookup and encryption keys from a room password (the first 32 bytes of the shared fingerprint). lookupKey (32B) is the relay index (base64 Bearer token); encryptionKey (32B) encrypts registration data with ChaCha20-Poly1305.

func Encrypt

func Encrypt(kek, plainText []byte) ([]byte, error)

Encrypt encrypts plainText using KEK with ChaCha20-Poly1305. Returns [nonce | ciphertext+MAC], or error.

func EncryptChunked

func EncryptChunked(kek []byte, r io.Reader, w io.Writer, plainSize uint64) error

func EncryptWithAAD added in v0.2.0

func EncryptWithAAD(kek, plainText, aad []byte) ([]byte, error)

EncryptWithAAD encrypts plainText with KEK using ChaCha20-Poly1305. The aad is authenticated but not included in the ciphertext; pass nil for none. It returns [nonce | ciphertext+MAC].

func EncryptWithNonce

func EncryptWithNonce(kek, plainText []byte, nonce [NonceSize]byte) ([]byte, error)

EncryptWithNonce encrypts with a caller-provided nonce, for counter-based encryption. It returns [nonce | ciphertext+MAC].

func EncryptedSize

func EncryptedSize(plainSize uint64) uint64

func EphemeralFoldRespond added in v0.4.0

func EphemeralFoldRespond(initMLKEMPub, initX25519Pub, salt []byte) (foldSecret, mlkemCiphertext, respX25519Pub []byte, err error)

EphemeralFoldRespond completes the responder's side: generate an ephemeral X25519 keypair, encapsulate to the initiator's ML-KEM public, X25519 ECDH, combine (salted) into the 32-byte fold secret. Returns the fold secret, ML-KEM ciphertext, and responder X25519 public for the initiator to finish. The constructors validate the initiator publics.

func ExtractRoomPassword

func ExtractRoomPassword(fingerprint string) ([]byte, error)

ExtractRoomPassword extracts the first 32 bytes from a base64-encoded fingerprint. Peers share this room password out-of-band; it derives the relay encryption keys.

func Fingerprint

func Fingerprint(pub []byte) string

func GenerateSeed

func GenerateSeed() []byte

func GenerateX25519Keypair

func GenerateX25519Keypair() (*ecdh.PrivateKey, *ecdh.PublicKey, error)

func HasHardwareAES

func HasHardwareAES() bool

HasHardwareAES reports whether the CPU has hardware AES acceleration. x86 uses AES-NI; ARM64 uses the ARMv8 AES extension.

func NewAEAD

func NewAEAD(suite CipherSuite, key []byte) (cipher.AEAD, error)

NewAEAD creates an AEAD cipher for the given suite and key. Both AES-256-GCM and ChaCha20-Poly1305 use 32-byte keys, 12-byte nonces, and 16-byte auth tags; the wire format is identical.

func ProtocolFingerprintV0

func ProtocolFingerprintV0(pubkeys map[string][]byte) (string, error)

ProtocolFingerprintV0 computes a stable fingerprint hash of ordered public keys.

func RandomBytes

func RandomBytes(size int) ([]byte, error)

func RatchetKeys added in v0.4.0

func RatchetKeys(prevCK []byte, prefix uint32, epoch uint16, foldSecret []byte) (ck, mk []byte, err error)

RatchetKeys derives the chaining key and message key for one epoch from the previous chaining key via HKDF-SHA512, with a per-direction, per-epoch salt and distinct CK/MK labels. MK is independent of the forward-carried CK, so leaking the AEAD key does not reveal the chain.

foldSecret empty = plain forward ratchet (forward secrecy rests on the previous CK being one-way and zeroized by the caller). Non-empty = post-compromise heal: the staged 32-byte KEM secret is mixed as extra IKM under distinct fold labels, so a folded epoch never collides with the plain one and the reader derives both and commits whichever authenticates.

func ValidateSeed

func ValidateSeed(s []byte) error

func X25519Decapsulate

func X25519Decapsulate(ciphertext []byte, recipientPriv *ecdh.PrivateKey, senderPub *ecdh.PublicKey) ([]byte, error)

func X25519Encapsulate

func X25519Encapsulate(seed []byte, senderPriv *ecdh.PrivateKey, recipientPub *ecdh.PublicKey) ([]byte, error)

Types

type CipherSuite

type CipherSuite string

CipherSuite identifies an AEAD cipher for the encrypted connection.

const (
	CipherChaCha20 CipherSuite = "chacha20-poly1305"
	CipherAES256   CipherSuite = "aes-256-gcm"
)

func NegotiateCipher

func NegotiateCipher(local, remote []CipherSuite) CipherSuite

NegotiateCipher picks the best cipher both peers support. It returns the first cipher from local that also appears in remote, or ChaCha20 when none matches.

func SupportedCiphers

func SupportedCiphers() []CipherSuite

SupportedCiphers returns the cipher suites this peer supports, ordered by preference (best first).

type FoldInitiator added in v0.4.0

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

FoldInitiator holds one fold round's ephemeral private keys for the initiator (the lower-fingerprint peer). Single-round lifetime: forward secrecy rests on these ephemeral keys not outliving the round.

func NewFoldInitiator added in v0.4.0

func NewFoldInitiator() (*FoldInitiator, error)

NewFoldInitiator generates the initiator's ephemeral ML-KEM-1024 and X25519 keypairs.

func (*FoldInitiator) Derive added in v0.4.0

func (fi *FoldInitiator) Derive(mlkemCiphertext, respX25519Pub, salt []byte) ([]byte, error)

Derive completes the initiator's side: decapsulate the responder's ML-KEM ciphertext, X25519 ECDH with its ephemeral public, combine (salted) into the 32-byte fold secret. The constructor validates the responder public. Keys drop on return, best-effort; Go has no wipe for these types, so single-round lifetime is the real control.

func (*FoldInitiator) MLKEMPublic added in v0.4.0

func (fi *FoldInitiator) MLKEMPublic() []byte

MLKEMPublic returns the initiator's ephemeral ML-KEM public to send to the responder.

func (*FoldInitiator) X25519Public added in v0.4.0

func (fi *FoldInitiator) X25519Public() []byte

X25519Public returns the initiator's ephemeral X25519 public to send to the responder.

type NonceGenerator

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

NonceGenerator provides deterministic per-direction AEAD nonces of the form [4-byte prefix][2-byte big-endian epoch][6-byte big-endian counter] = 12 bytes. The prefix distinguishes directions. The ratchet bumps the epoch (key generation); the 48-bit counter resets to 0 on each bump. Epoch and counter share one atomic word so every Next reads a consistent pair; the caller serializes SetEpoch against Next. At epoch 0 the layout is byte-identical to the old [4-byte prefix][8-byte counter] format, so a ratchet-unaware peer stays interoperable until the first bump.

func NewNonceGenerator

func NewNonceGenerator(prefix uint32) *NonceGenerator

NewNonceGenerator creates a nonce generator with the given prefix. Use different prefixes for inbound vs outbound to avoid nonce reuse.

func (*NonceGenerator) Count

func (ng *NonceGenerator) Count() uint64

Count returns the current per-epoch counter (for monitoring/debugging).

func (*NonceGenerator) Epoch added in v0.4.0

func (ng *NonceGenerator) Epoch() uint16

Epoch returns the current key epoch, the high 16 bits of the state (for monitoring).

func (*NonceGenerator) Next

func (ng *NonceGenerator) Next() ([NonceSize]byte, error)

Next returns the next nonce and advances the counter. Thread-safe. Returns ErrNonceOverflow if the 48-bit counter would wrap within an epoch, since a wrap carries into the epoch bytes and reuses a (key, nonce) pair.

func (*NonceGenerator) SetEpoch added in v0.4.0

func (ng *NonceGenerator) SetEpoch(epoch uint16)

SetEpoch installs a new key epoch and resets the counter, so the next Next emits counter 1 under that epoch. The caller must serialize SetEpoch against Next.

type OwnKeys

type OwnKeys struct {
	MlKemPrivate *mlkem.DecapsulationKey1024
	MlKemPublic  *mlkem.EncapsulationKey1024

	X25519Private *ecdh.PrivateKey
	X25519Public  *ecdh.PublicKey
}

func (*OwnKeys) ExportPubKeysAsMap

func (ok *OwnKeys) ExportPubKeysAsMap() (map[string]string, error)

func (*OwnKeys) Fingerprint

func (ok *OwnKeys) Fingerprint() (string, error)

func (*OwnKeys) Validate

func (ok *OwnKeys) Validate() error

type PeerKeys

type PeerKeys struct {
	MlKemPublic  *mlkem.EncapsulationKey1024
	X25519Public *ecdh.PublicKey
}

func ParsePeerKeys

func ParsePeerKeys(pubMap map[string][]byte) (*PeerKeys, error)

func (*PeerKeys) Fingerprint

func (pk *PeerKeys) Fingerprint() (string, error)

func (*PeerKeys) Validate

func (pk *PeerKeys) Validate() error

Jump to

Keyboard shortcuts

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