Documentation
¶
Index ¶
- Constants
- Variables
- func Decrypt(kek, input []byte) ([]byte, error)
- func DecryptChunked(kek []byte, r io.Reader, w io.Writer, cipherSize uint64) error
- func DecryptWithAAD(kek, input, aad []byte) ([]byte, error)
- func DecryptedSize(cipherSize uint64) (uint64, error)
- func DeriveAES256Key(sharedSecrets ...[]byte) ([]byte, error)
- func DeriveChaCha20Key(sharedSecrets ...[]byte) ([]byte, error)
- func DeriveFileEncryptionKey(masterKey, salt []byte, info string) ([]byte, error)
- func DeriveFoldSalt(ikm []byte) ([]byte, error)
- func DeriveKey(suite CipherSuite, sharedSecrets ...[]byte) ([]byte, error)
- func DerivePresenceKey(posterFingerprint, checkerFingerprint string) ([]byte, error)
- func DeriveRelayKeys(roomPassword []byte) (lookupKey []byte, encryptionKey []byte, err error)
- func Encrypt(kek, plainText []byte) ([]byte, error)
- func EncryptChunked(kek []byte, r io.Reader, w io.Writer, plainSize uint64) error
- func EncryptWithAAD(kek, plainText, aad []byte) ([]byte, error)
- func EncryptWithNonce(kek, plainText []byte, nonce [NonceSize]byte) ([]byte, error)
- func EncryptedSize(plainSize uint64) uint64
- func EphemeralFoldRespond(initMLKEMPub, initX25519Pub, salt []byte) (foldSecret, mlkemCiphertext, respX25519Pub []byte, err error)
- func ExtractRoomPassword(fingerprint string) ([]byte, error)
- func Fingerprint(pub []byte) string
- func GenerateMLKEMKeypair() (*mlkem.DecapsulationKey1024, *mlkem.EncapsulationKey1024, error)
- func GenerateSeed() []byte
- func GenerateX25519Keypair() (*ecdh.PrivateKey, *ecdh.PublicKey, error)
- func HasHardwareAES() bool
- func NewAEAD(suite CipherSuite, key []byte) (cipher.AEAD, error)
- func ProtocolFingerprintV0(pubkeys map[string][]byte) (string, error)
- func RandomBytes(size int) ([]byte, error)
- func RatchetKeys(prevCK []byte, prefix uint32, epoch uint16, foldSecret []byte) (ck, mk []byte, err error)
- func ValidateSeed(s []byte) error
- func X25519Decapsulate(ciphertext []byte, recipientPriv *ecdh.PrivateKey, senderPub *ecdh.PublicKey) ([]byte, error)
- func X25519Encapsulate(seed []byte, senderPriv *ecdh.PrivateKey, recipientPub *ecdh.PublicKey) ([]byte, error)
- type CipherSuite
- type FoldInitiator
- type NonceGenerator
- type OwnKeys
- type PeerKeys
Constants ¶
const BlockSize = uint64(2 << 16) // Double the block size that linux cp uses.
const EncOverhead = uint64(chacha20poly1305.NonceSize + chacha20poly1305.Overhead)
const KeySize = chacha20poly1305.KeySize
const NonceSize = chacha20poly1305.NonceSize
Variables ¶
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 ¶
Decrypt decrypts [nonce | ciphertext+MAC] using KEK. Returns plainText or error if authentication fails.
func DecryptChunked ¶
func DecryptWithAAD ¶ added in v0.2.0
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 DeriveAES256Key ¶
DeriveAES256Key derives a 32-byte symmetric key for AES-256-GCM. A different HKDF label keeps domain separation from ChaCha20 keys.
func DeriveChaCha20Key ¶
DeriveChaCha20Key derives a 32-byte symmetric key using SHA-512 over the given secrets.
func DeriveFileEncryptionKey ¶ added in v0.2.0
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
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
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 ¶
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 ¶
Encrypt encrypts plainText using KEK with ChaCha20-Poly1305. Returns [nonce | ciphertext+MAC], or error.
func EncryptChunked ¶
func EncryptWithAAD ¶ added in v0.2.0
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 ¶
EncryptWithNonce encrypts with a caller-provided nonce, for counter-based encryption. It returns [nonce | ciphertext+MAC].
func EncryptedSize ¶
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 ¶
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 GenerateMLKEMKeypair ¶
func GenerateMLKEMKeypair() (*mlkem.DecapsulationKey1024, *mlkem.EncapsulationKey1024, error)
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 ¶
ProtocolFingerprintV0 computes a stable fingerprint hash of ordered public keys.
func RandomBytes ¶
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 X25519Decapsulate ¶
func X25519Encapsulate ¶
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 (*OwnKeys) Fingerprint ¶
type PeerKeys ¶
type PeerKeys struct {
MlKemPublic *mlkem.EncapsulationKey1024
X25519Public *ecdh.PublicKey
}